From 5f5c6c5f579c7693ce316f3691b2f971d6dd3559 Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Fri, 27 Nov 2020 19:14:03 -0300 Subject: [PATCH 01/16] deal with branches while decompiling --- .classpath | 21 +- .../internal/BranchInstructionFlow.java | 83 + .../java/lang/jimple/internal/Decompiler.java | 1746 ++++++++++------- .../lang/jimple/internal/InstructionFlow.java | 16 + .../jimple/internal/JimpleObjectFactory.java | 5 - .../java/lang/jimple/internal/Operand.java | 28 + .../internal/SingleInstructionFlow.java | 46 + .../jimple/internal/generated/Statement.java | 1392 +++++++------ src/main/rascal/lang/jimple/core/Syntax.rsc | 2 +- src/test/java/samples/operators/IntOps.java | 247 +-- 10 files changed, 2012 insertions(+), 1574 deletions(-) create mode 100644 src/main/java/lang/jimple/internal/BranchInstructionFlow.java create mode 100644 src/main/java/lang/jimple/internal/InstructionFlow.java create mode 100644 src/main/java/lang/jimple/internal/Operand.java create mode 100644 src/main/java/lang/jimple/internal/SingleInstructionFlow.java diff --git a/.classpath b/.classpath index 389fc025..300190ff 100644 --- a/.classpath +++ b/.classpath @@ -1,8 +1,19 @@ - + + + + + + - + + + + + + + @@ -15,5 +26,11 @@ + + + + + + diff --git a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java new file mode 100644 index 00000000..0139f8eb --- /dev/null +++ b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java @@ -0,0 +1,83 @@ +package lang.jimple.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import lang.jimple.internal.generated.Expression; +import lang.jimple.internal.generated.Statement; + +public class BranchInstructionFlow implements InstructionFlow { + + private Expression condition; + private String target; + private InstructionFlow left; + private InstructionFlow right; + private BranchState status; + + enum BranchState { + LEFT, + RIGHT, + ReadyToMerge; + } + + public BranchInstructionFlow(Expression condition, String target) { + this.condition = condition; + this.target = target; + left = new SingleInstructionFlow(); + right = new SingleInstructionFlow(); + status = BranchState.LEFT; + } + + public void push(Operand operand) { + switch(status) { + case LEFT: left.push(operand); break; + case RIGHT: right.push(operand); break; + case ReadyToMerge: left.push(operand); right.push(operand); + } + } + + public Operand pop() { + switch(status) { + case LEFT: return left.pop(); + case RIGHT: return right.pop(); + case ReadyToMerge: return null; + } + return null; + } + + public void addInstruction(Statement stmt) { + switch(status) { + case LEFT: left.addInstruction(stmt); break; + case RIGHT: right.addInstruction(stmt); break; + case ReadyToMerge: left.addInstruction(stmt); right.addInstruction(stmt); + } + } + + public void clearOperandStack() { + left.clearOperandStack(); + right.clearOperandStack(); + } + + @Override + public int sizeOfOperandStack() { + switch(status) { + case LEFT: return left.sizeOfOperandStack(); + case RIGHT: return right.sizeOfOperandStack(); + case ReadyToMerge: return left.sizeOfOperandStack() + right.sizeOfOperandStack(); + } + return 0; + } + + @Override + public Collection merge() { + List res = new ArrayList<>(); + + res.add(Statement.ifStmt(condition, target)); + res.addAll(left.merge()); + res.addAll(right.merge()); + + return res; + } + +} diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index c41d184c..ad5cd7d6 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -75,7 +76,7 @@ */ public class Decompiler { private static final String INVOKE_DYNAMIC_FAKE_CLASS = "lang.jimple.InvokeDynamic"; - + private static final String LOCAL_VARIABLE_PARAMETER_PREFIX = "i"; private static final String LOCAL_VARIABLE_PREFIX = "i"; private static final String SATCK_BASED_LOCAL_VARIABLE_PREFIX = "$r"; @@ -84,10 +85,9 @@ public class Decompiler { private static final String IMPLICIT_PARAMETER_NAME = "@this"; private static final String LOCAL_NAME_FOR_IMPLICIT_PARAMETER = "r0"; - private final IValueFactory vf; private IConstructor _class; - + public Decompiler(IValueFactory vf) { this.vf = vf; } @@ -96,14 +96,13 @@ public Decompiler(IValueFactory vf) { * decompiles a Java byte code at classLoc into a Jimple representation. */ public IConstructor decompile(ISourceLocation classLoc, IEvaluatorContext ctx) { - try { + try { return decompile(URIResolverRegistry.getInstance().getInputStream(classLoc), ctx); - } - catch (IOException e) { + } catch (IOException e) { throw RuntimeExceptionFactory.io(vf.string(e.getMessage()), null, null); } } - + public IConstructor decompile(InputStream classLoc, IEvaluatorContext ctx) { try { ClassReader reader = new ClassReader(classLoc); @@ -115,8 +114,7 @@ public IConstructor decompile(InputStream classLoc, IEvaluatorContext ctx) { throw RuntimeExceptionFactory.io(vf.string(e.getMessage()), null, null); } } - - + /* * an ASM class visitor that traverses a class byte code and generates a Jimple * class. @@ -137,10 +135,12 @@ public GenerateJimpleClassVisitor(ClassNode cn) { } @Override - public void visit(int version, int access, String name, String signature, String superClass, String[] interfaces) { + public void visit(int version, int access, String name, String signature, String superClass, + String[] interfaces) { this.classModifiers = modifiers(access); this.type = objectConstructor(name); - this.superClass = superClass != null ? objectConstructor(superClass) : objectConstructor("java.lang.Object"); + this.superClass = superClass != null ? objectConstructor(superClass) + : objectConstructor("java.lang.Object"); this.interfaces = new ArrayList<>(); if (interfaces != null) { @@ -158,11 +158,11 @@ public void visit(int version, int access, String name, String signature, String @Override public void visitEnd() { Iterator it = cn.methods.iterator(); - - while(it.hasNext()) { - visitMethod((MethodNode)it.next()); + + while (it.hasNext()) { + visitMethod((MethodNode) it.next()); } - + if (isInterface) { _class = ClassOrInterfaceDeclaration.interfaceDecl(type, classModifiers, interfaces, fields, methods) .createVallangInstance(vf); @@ -177,58 +177,58 @@ private void visitMethod(MethodNode mn) { List methodModifiers = modifiers(mn.access); Type methodReturnType = type(org.objectweb.asm.Type.getReturnType(mn.desc).getDescriptor()); String methodName = mn.name; - + List methodFormalArgs = new ArrayList<>(); List methodExceptions = new ArrayList<>(); - - - for(org.objectweb.asm.Type t: org.objectweb.asm.Type.getArgumentTypes(mn.desc)) { + + for (org.objectweb.asm.Type t : org.objectweb.asm.Type.getArgumentTypes(mn.desc)) { methodFormalArgs.add(type(t.getDescriptor())); } - - if(mn.exceptions != null) { - Iterator it = mn.exceptions.iterator(); - - while(it.hasNext()) { - String str = (String)it.next(); - methodExceptions.add(objectConstructor(str)); - } + + if (mn.exceptions != null) { + Iterator it = mn.exceptions.iterator(); + + while (it.hasNext()) { + String str = (String) it.next(); + methodExceptions.add(objectConstructor(str)); + } } - + boolean isStatic = methodModifiers.contains(Modifier.Static()); - - HashMap localVariables = visitLocalVariables(isStatic, methodFormalArgs.size(), mn.localVariables); - + + HashMap localVariables = visitLocalVariables(isStatic, + methodFormalArgs.size(), mn.localVariables); + List decls = new ArrayList<>(); List stmts = new ArrayList<>(); List catchClauses = visitTryCatchBlocks(mn.tryCatchBlocks); - - + InstructionSetVisitor insVisitor = new InstructionSetVisitor(Opcodes.ASM4, localVariables, catchClauses); - + insVisitor.initFormalArgs(isStatic, this.type, localVariables.isEmpty(), methodFormalArgs); - + mn.instructions.accept(insVisitor); - - // TODO: we commented this line because we want to - // solve this issue using a Jimple transformation. - // we will keep the commented implementation here just while - // we review the new strategy. - // + + // TODO: we commented this line because we want to + // solve this issue using a Jimple transformation. + // we will keep the commented implementation here just while + // we review the new strategy. + // // insVisitor.clearUnusedLabelInstructions(); - - stmts = insVisitor.instructions; - - for(LocalVariableDeclaration var: localVariables.values()) { + + stmts = insVisitor.instructions(); + + for (LocalVariableDeclaration var : localVariables.values()) { decls.add(var); } - for(LocalVariableDeclaration var: insVisitor.auxiliarlyLocalVariables) { + for (LocalVariableDeclaration var : insVisitor.auxiliarlyLocalVariables) { decls.add(var); } - - MethodBody methodBody = MethodBody.methodBody(decls, stmts, catchClauses); - - methods.add(Method.method(methodModifiers, methodReturnType, methodName, methodFormalArgs, methodExceptions, methodBody)); + + MethodBody methodBody = MethodBody.methodBody(decls, stmts, catchClauses); + + methods.add(Method.method(methodModifiers, methodReturnType, methodName, methodFormalArgs, methodExceptions, + methodBody)); } @Override @@ -241,23 +241,23 @@ public FieldVisitor visitField(int access, String name, String descriptor, Strin return super.visitField(access, name, descriptor, signature, value); } - private HashMap visitLocalVariables(boolean isStatic, int formals, List nodes) { + private HashMap visitLocalVariables(boolean isStatic, int formals, + List nodes) { HashMap localVariables = new HashMap<>(); - - int idx = 1; - - if(nodes != null) { - for(int i = 0; i < nodes.size(); i++) { - String name = ""; + + int idx = 1; + + if (nodes != null) { + for (int i = 0; i < nodes.size(); i++) { + String name = ""; LocalVariableNode var = nodes.get(i); Type type = type(var.desc); - if(!isStatic && i == 0 && var.name.equals(THIS_VARIABLE)) { // being really conservative here. - name = LOCAL_NAME_FOR_IMPLICIT_PARAMETER; // DO NOT INCREMENT idx here - } - else { - name = JimpleObjectFactory.localVariableName(false, type.getConstructor(), idx++); + if (!isStatic && i == 0 && var.name.equals(THIS_VARIABLE)) { // being really conservative here. + name = LOCAL_NAME_FOR_IMPLICIT_PARAMETER; // DO NOT INCREMENT idx here + } else { + name = JimpleObjectFactory.localVariableName(false, type.getConstructor(), idx++); } - localVariables.put(var, LocalVariableDeclaration.localVariableDeclaration(type, name)); + localVariables.put(var, LocalVariableDeclaration.localVariableDeclaration(type, name)); } } return localVariables; @@ -265,73 +265,78 @@ private HashMap visitLocalVariables private List visitTryCatchBlocks(List nodes) { List tryCatchBlocks = new ArrayList<>(); - for(TryCatchBlockNode node: nodes) { - String from = node.start.getLabel().toString(); - String to = node.end.getLabel().toString(); - String with = node.handler.getLabel().toString(); - - Type exception = objectConstructor(node.type); - - tryCatchBlocks.add(CatchClause.catchClause(exception, from, to, with)); + for (TryCatchBlockNode node : nodes) { + String from = node.start.getLabel().toString(); + String to = node.end.getLabel().toString(); + String with = node.handler.getLabel().toString(); + + Type exception = objectConstructor(node.type); + + tryCatchBlocks.add(CatchClause.catchClause(exception, from, to, with)); } return tryCatchBlocks; } } - class InstructionSetVisitor extends org.objectweb.asm.MethodVisitor { - - class Operand { - Type type; - Immediate immediate; - - Operand(Type type, Immediate immediate) { - this.type = type; - this.immediate = immediate; - } - Operand(LocalVariableDeclaration localDeclaration) { - this.type = localDeclaration.varType; - this.immediate = Immediate.local(localDeclaration.local); - } - - Operand(Pair typedValue) { - this.type = typedValue.getFirst(); - this.immediate = Immediate.iValue(typedValue.getSecond()); - } - } - Stack operandStack; + class InstructionSetVisitor extends org.objectweb.asm.MethodVisitor { + + Stack stack; + List auxiliarlyLocalVariables; HashMap localVariables; int locals; - List instructions; - // we use this set to keep track of the referenced labels. - // afterwards we can remove labeled instructions that are - // not refered to in the bytecode. - Set referencedLabels = new HashSet<>(); - - HashMap catchClauses = new HashMap<>(); + // afterwards we can remove labeled instructions that are + // not refered to in the bytecode. + Set referencedLabels = new HashSet<>(); + + HashMap catchClauses = new HashMap<>(); public InstructionSetVisitor(int version, HashMap localVariables, List catchClauses) { super(version); this.localVariables = localVariables; - operandStack = new Stack<>(); auxiliarlyLocalVariables = new ArrayList<>(); - locals = 1; // localVariables.size(); - instructions = new ArrayList<>(); + locals = 1; catchClauses.forEach(c -> this.catchClauses.put(c.with, c)); + + stack = new Stack<>(); + stack.push(new SingleInstructionFlow()); + } + + public List instructions() { + return new ArrayList<>(stack.peek().merge()); + } + + private void addInstruction(Statement s) { + stack.peek().addInstruction(s); + } + + private void pushOperand(Operand o) { + stack.peek().push(o); + } + + private Operand pop() { + return stack.peek().pop(); + } + + private int sizeOfOperandStack() { + return stack.peek().sizeOfOperandStack(); + } + private void notifyReturn() { + stack.peek().clearOperandStack(); } @Override public void visitLabel(Label label) { - instructions.add(Statement.label(label.toString())); - if(catchClauses.containsKey(label.toString())) { + addInstruction(Statement.label(label.toString())); + if (catchClauses.containsKey(label.toString())) { CatchClause c = catchClauses.get(label.toString()); - operandStack.push(new Operand(c.exception, Immediate.caughtException())); + pushOperand(new Operand(c.exception, Immediate.caughtException())); referencedLabels.add(label.toString()); } } @@ -343,11 +348,20 @@ public void visitLabel(Label label) { @Override public void visitFieldInsn(int opcode, String owner, String field, String descriptor) { switch (opcode) { - case Opcodes.GETSTATIC : getStaticIns(owner, field, descriptor); break; - case Opcodes.PUTSTATIC : putStaticIns(owner, field, descriptor); break; - case Opcodes.GETFIELD : getFieldIns(owner, field, descriptor); break; - case Opcodes.PUTFIELD : putFieldIns(owner, field, descriptor); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + case Opcodes.GETSTATIC: + getStaticIns(owner, field, descriptor); + break; + case Opcodes.PUTSTATIC: + putStaticIns(owner, field, descriptor); + break; + case Opcodes.GETFIELD: + getFieldIns(owner, field, descriptor); + break; + case Opcodes.PUTFIELD: + putFieldIns(owner, field, descriptor); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } super.visitFieldInsn(opcode, owner, field, descriptor); } @@ -357,10 +371,13 @@ public void visitFieldInsn(int opcode, String owner, String field, String descri * operand stack. * * @param idx index of the local variable + * * @increment ammount of the increment. * * (non-Javadoc) + * * @see org.objectweb.asm.MethodVisitor#visitIincInsn(int, int) + * * @see * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.iinc */ @@ -374,374 +391,668 @@ public void visitIincInsn(int idx, int increment) { Immediate rhs = newIntValueImmediate(increment); Expression expression = newPlusExpression(lhs, rhs); - instructions.add(assignmentStmt(Variable.localVariable(var), expression)); - + addInstruction(assignmentStmt(Variable.localVariable(var), expression)); + super.visitIincInsn(idx, increment); } - @Override public void visitInsn(int opcode) { switch (opcode) { - case Opcodes.NOP : nopIns(); break; - case Opcodes.ACONST_NULL : acconstNullIns(); break; - case Opcodes.ICONST_M1 : loadIntConstIns(-1,"I"); break; - case Opcodes.ICONST_0 : loadIntConstIns(0, "I"); break; - case Opcodes.ICONST_1 : loadIntConstIns(1, "I"); break; - case Opcodes.ICONST_2 : loadIntConstIns(2, "I"); break; - case Opcodes.ICONST_3 : loadIntConstIns(3, "I"); break; - case Opcodes.ICONST_4 : loadIntConstIns(4, "I"); break; - case Opcodes.ICONST_5 : loadIntConstIns(5, "I"); break; - case Opcodes.LCONST_0 : loadIntConstIns(0, "J"); break; - case Opcodes.LCONST_1 : loadIntConstIns(1, "J"); break; - case Opcodes.FCONST_0 : loadRealConstIns(0.0F, "F"); break; - case Opcodes.FCONST_1 : loadRealConstIns(1.0F, "F"); break; - case Opcodes.FCONST_2 : loadRealConstIns(2.0F, "F"); break; - case Opcodes.DCONST_0 : loadRealConstIns(0.0F, "F"); break; - case Opcodes.DCONST_1 : loadRealConstIns(1.0F, "F"); break; - case Opcodes.IALOAD : arraySubscriptIns(); break; - case Opcodes.LALOAD : arraySubscriptIns(); break; - case Opcodes.FALOAD : arraySubscriptIns(); break; - case Opcodes.DALOAD : arraySubscriptIns(); break; - case Opcodes.AALOAD : arraySubscriptIns(); break; - case Opcodes.BALOAD : arraySubscriptIns(); break; - case Opcodes.CALOAD : arraySubscriptIns(); break; - case Opcodes.SALOAD : arraySubscriptIns(); break; - case Opcodes.IASTORE : storeIntoArrayIns(); break; - case Opcodes.LASTORE : storeIntoArrayIns(); break; - case Opcodes.FASTORE : storeIntoArrayIns(); break; - case Opcodes.DASTORE : storeIntoArrayIns(); break; - case Opcodes.AASTORE : storeIntoArrayIns(); break; - case Opcodes.BASTORE : storeIntoArrayIns(); break; - case Opcodes.CASTORE : storeIntoArrayIns(); break; - case Opcodes.SASTORE : storeIntoArrayIns(); break; - case Opcodes.POP : popIns(); break; - case Opcodes.POP2 : pop2Ins(); break; - case Opcodes.DUP : dupIns(); break; - case Opcodes.DUP_X1 : dupX1Ins(); break; - case Opcodes.DUP_X2 : dupX2Ins(); break; - case Opcodes.DUP2 : dup2Ins(); break; - case Opcodes.DUP2_X1 : dup2X1Ins(); break; - case Opcodes.DUP2_X2 : dup2X2Ins(); break; - case Opcodes.SWAP : swapIns(); break; - case Opcodes.IADD : binOperatorIns(type("I"), (l, r) -> newPlusExpression(l, r)); break; - case Opcodes.LADD : binOperatorIns(type("J"), (l, r) -> newPlusExpression(l, r)); break; - case Opcodes.FADD : binOperatorIns(type("F"), (l, r) -> newPlusExpression(l, r)); break; - case Opcodes.DADD : binOperatorIns(type("D"), (l, r) -> newPlusExpression(l, r)); break; - case Opcodes.ISUB : binOperatorIns(type("I"), (l, r) -> newMinusExpression(l, r)); break; - case Opcodes.LSUB : binOperatorIns(type("J"), (l, r) -> newMinusExpression(l, r)); break; - case Opcodes.FSUB : binOperatorIns(type("F"), (l, r) -> newMinusExpression(l, r)); break; - case Opcodes.DSUB : binOperatorIns(type("D"), (l, r) -> newMinusExpression(l, r)); break; - case Opcodes.IMUL : binOperatorIns(type("I"), (l, r) -> newMultExpression(l, r)); break; - case Opcodes.LMUL : binOperatorIns(type("J"), (l, r) -> newMultExpression(l, r)); break; - case Opcodes.FMUL : binOperatorIns(type("F"), (l, r) -> newMultExpression(l, r)); break; - case Opcodes.DMUL : binOperatorIns(type("D"), (l, r) -> newMultExpression(l, r)); break; - case Opcodes.IDIV : binOperatorIns(type("I"), (l, r) -> newDivExpression(l, r)); break; - case Opcodes.LDIV : binOperatorIns(type("J"), (l, r) -> newDivExpression(l, r)); break; - case Opcodes.FDIV : binOperatorIns(type("F"), (l, r) -> newDivExpression(l, r)); break; - case Opcodes.DDIV : binOperatorIns(type("D"), (l, r) -> newDivExpression(l, r)); break; - case Opcodes.IREM : binOperatorIns(type("I"), (l, r) -> newReminderExpression(l, r)); break; - case Opcodes.LREM : binOperatorIns(type("J"), (l, r) -> newReminderExpression(l, r)); break; - case Opcodes.FREM : binOperatorIns(type("F"), (l, r) -> newReminderExpression(l, r)); break; - case Opcodes.DREM : binOperatorIns(type("D"), (l, r) -> newReminderExpression(l, r)); break; - case Opcodes.INEG : negIns(type("I")); break; - case Opcodes.LNEG : negIns(type("J")); break; - case Opcodes.FNEG : negIns(type("F")); break; - case Opcodes.DNEG : negIns(type("D")); break; - case Opcodes.ISHL : binOperatorIns(type("I"), (l, r) -> Expression.shl(l, r)); break; - case Opcodes.LSHL : binOperatorIns(type("J"), (l, r) -> Expression.shl(l, r)); break; - case Opcodes.ISHR : binOperatorIns(type("I"), (l, r) -> Expression.shr(l, r)); break; - case Opcodes.LSHR : binOperatorIns(type("J"), (l, r) -> Expression.shr(l, r)); break; - case Opcodes.IUSHR : binOperatorIns(type("I"), (l, r) -> Expression.ushr(l, r)); break; - case Opcodes.LUSHR : binOperatorIns(type("J"), (l, r) -> Expression.ushr(l, r)); break; - case Opcodes.IAND : binOperatorIns(type("I"), (l, r) -> Expression.and(l, r)); break; - case Opcodes.LAND : binOperatorIns(type("J"), (l, r) -> Expression.and(l, r)); break; - case Opcodes.IOR : binOperatorIns(type("I"), (l, r) -> Expression.or(l, r)); break; - case Opcodes.LOR : binOperatorIns(type("J"), (l, r) -> Expression.or(l, r)); break; - case Opcodes.IXOR : binOperatorIns(type("I"), (l, r) -> Expression.xor(l, r)); break; - case Opcodes.LXOR : binOperatorIns(type("J"), (l, r) -> Expression.xor(l, r)); break; - case Opcodes.I2L : simpleCastIns(type("J")); break; - case Opcodes.I2F : simpleCastIns(type("F")); break; - case Opcodes.I2D : simpleCastIns(type("D")); break; - case Opcodes.L2I : simpleCastIns(type("I")); break; - case Opcodes.L2F : simpleCastIns(type("F")); break; - case Opcodes.L2D : simpleCastIns(type("D")); break; - case Opcodes.F2I : simpleCastIns(type("I")); break; - case Opcodes.F2L : simpleCastIns(type("J")); break; - case Opcodes.F2D : simpleCastIns(type("D")); break; - case Opcodes.D2I : simpleCastIns(type("I")); break; - case Opcodes.D2L : simpleCastIns(type("J")); break; - case Opcodes.D2F : simpleCastIns(type("F")); break; - case Opcodes.I2B : simpleCastIns(type("B")); break; - case Opcodes.I2C : simpleCastIns(type("C")); break; - case Opcodes.I2S : simpleCastIns(type("S")); break; - case Opcodes.LCMP : binOperatorIns(type("I"), (l, r) -> Expression.cmp(l, r)); break; - case Opcodes.FCMPG : binOperatorIns(type("I"), (l, r) -> Expression.cmpg(l, r)); break; - case Opcodes.FCMPL : binOperatorIns(type("I"), (l, r) -> Expression.cmpl(l, r)); break; - case Opcodes.DCMPG : binOperatorIns(type("I"), (l, r) -> Expression.cmpg(l, r)); break; - case Opcodes.DCMPL : binOperatorIns(type("I"), (l, r) -> Expression.cmpl(l, r)); break; - case Opcodes.IRETURN : returnIns(); break; - case Opcodes.LRETURN : returnIns(); break; - case Opcodes.FRETURN : returnIns(); break; - case Opcodes.DRETURN : returnIns(); break; - case Opcodes.ARETURN : returnIns(); break; - case Opcodes.RETURN : returnVoidIns(); break; - case Opcodes.ARRAYLENGTH : arrayLengthIns(); break; - case Opcodes.ATHROW : throwIns(); break; - case Opcodes.MONITORENTER : monitorEnterIns(); break; - case Opcodes.MONITOREXIT : monitorExitIns(); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + case Opcodes.NOP: + nopIns(); + break; + case Opcodes.ACONST_NULL: + acconstNullIns(); + break; + case Opcodes.ICONST_M1: + loadIntConstIns(-1, "I"); + break; + case Opcodes.ICONST_0: + loadIntConstIns(0, "I"); + break; + case Opcodes.ICONST_1: + loadIntConstIns(1, "I"); + break; + case Opcodes.ICONST_2: + loadIntConstIns(2, "I"); + break; + case Opcodes.ICONST_3: + loadIntConstIns(3, "I"); + break; + case Opcodes.ICONST_4: + loadIntConstIns(4, "I"); + break; + case Opcodes.ICONST_5: + loadIntConstIns(5, "I"); + break; + case Opcodes.LCONST_0: + loadIntConstIns(0, "J"); + break; + case Opcodes.LCONST_1: + loadIntConstIns(1, "J"); + break; + case Opcodes.FCONST_0: + loadRealConstIns(0.0F, "F"); + break; + case Opcodes.FCONST_1: + loadRealConstIns(1.0F, "F"); + break; + case Opcodes.FCONST_2: + loadRealConstIns(2.0F, "F"); + break; + case Opcodes.DCONST_0: + loadRealConstIns(0.0F, "F"); + break; + case Opcodes.DCONST_1: + loadRealConstIns(1.0F, "F"); + break; + case Opcodes.IALOAD: + arraySubscriptIns(); + break; + case Opcodes.LALOAD: + arraySubscriptIns(); + break; + case Opcodes.FALOAD: + arraySubscriptIns(); + break; + case Opcodes.DALOAD: + arraySubscriptIns(); + break; + case Opcodes.AALOAD: + arraySubscriptIns(); + break; + case Opcodes.BALOAD: + arraySubscriptIns(); + break; + case Opcodes.CALOAD: + arraySubscriptIns(); + break; + case Opcodes.SALOAD: + arraySubscriptIns(); + break; + case Opcodes.IASTORE: + storeIntoArrayIns(); + break; + case Opcodes.LASTORE: + storeIntoArrayIns(); + break; + case Opcodes.FASTORE: + storeIntoArrayIns(); + break; + case Opcodes.DASTORE: + storeIntoArrayIns(); + break; + case Opcodes.AASTORE: + storeIntoArrayIns(); + break; + case Opcodes.BASTORE: + storeIntoArrayIns(); + break; + case Opcodes.CASTORE: + storeIntoArrayIns(); + break; + case Opcodes.SASTORE: + storeIntoArrayIns(); + break; + case Opcodes.POP: + popIns(); + break; + case Opcodes.POP2: + pop2Ins(); + break; + case Opcodes.DUP: + dupIns(); + break; + case Opcodes.DUP_X1: + dupX1Ins(); + break; + case Opcodes.DUP_X2: + dupX2Ins(); + break; + case Opcodes.DUP2: + dup2Ins(); + break; + case Opcodes.DUP2_X1: + dup2X1Ins(); + break; + case Opcodes.DUP2_X2: + dup2X2Ins(); + break; + case Opcodes.SWAP: + swapIns(); + break; + case Opcodes.IADD: + binOperatorIns(type("I"), (l, r) -> newPlusExpression(l, r)); + break; + case Opcodes.LADD: + binOperatorIns(type("J"), (l, r) -> newPlusExpression(l, r)); + break; + case Opcodes.FADD: + binOperatorIns(type("F"), (l, r) -> newPlusExpression(l, r)); + break; + case Opcodes.DADD: + binOperatorIns(type("D"), (l, r) -> newPlusExpression(l, r)); + break; + case Opcodes.ISUB: + binOperatorIns(type("I"), (l, r) -> newMinusExpression(l, r)); + break; + case Opcodes.LSUB: + binOperatorIns(type("J"), (l, r) -> newMinusExpression(l, r)); + break; + case Opcodes.FSUB: + binOperatorIns(type("F"), (l, r) -> newMinusExpression(l, r)); + break; + case Opcodes.DSUB: + binOperatorIns(type("D"), (l, r) -> newMinusExpression(l, r)); + break; + case Opcodes.IMUL: + binOperatorIns(type("I"), (l, r) -> newMultExpression(l, r)); + break; + case Opcodes.LMUL: + binOperatorIns(type("J"), (l, r) -> newMultExpression(l, r)); + break; + case Opcodes.FMUL: + binOperatorIns(type("F"), (l, r) -> newMultExpression(l, r)); + break; + case Opcodes.DMUL: + binOperatorIns(type("D"), (l, r) -> newMultExpression(l, r)); + break; + case Opcodes.IDIV: + binOperatorIns(type("I"), (l, r) -> newDivExpression(l, r)); + break; + case Opcodes.LDIV: + binOperatorIns(type("J"), (l, r) -> newDivExpression(l, r)); + break; + case Opcodes.FDIV: + binOperatorIns(type("F"), (l, r) -> newDivExpression(l, r)); + break; + case Opcodes.DDIV: + binOperatorIns(type("D"), (l, r) -> newDivExpression(l, r)); + break; + case Opcodes.IREM: + binOperatorIns(type("I"), (l, r) -> newReminderExpression(l, r)); + break; + case Opcodes.LREM: + binOperatorIns(type("J"), (l, r) -> newReminderExpression(l, r)); + break; + case Opcodes.FREM: + binOperatorIns(type("F"), (l, r) -> newReminderExpression(l, r)); + break; + case Opcodes.DREM: + binOperatorIns(type("D"), (l, r) -> newReminderExpression(l, r)); + break; + case Opcodes.INEG: + negIns(type("I")); + break; + case Opcodes.LNEG: + negIns(type("J")); + break; + case Opcodes.FNEG: + negIns(type("F")); + break; + case Opcodes.DNEG: + negIns(type("D")); + break; + case Opcodes.ISHL: + binOperatorIns(type("I"), (l, r) -> Expression.shl(l, r)); + break; + case Opcodes.LSHL: + binOperatorIns(type("J"), (l, r) -> Expression.shl(l, r)); + break; + case Opcodes.ISHR: + binOperatorIns(type("I"), (l, r) -> Expression.shr(l, r)); + break; + case Opcodes.LSHR: + binOperatorIns(type("J"), (l, r) -> Expression.shr(l, r)); + break; + case Opcodes.IUSHR: + binOperatorIns(type("I"), (l, r) -> Expression.ushr(l, r)); + break; + case Opcodes.LUSHR: + binOperatorIns(type("J"), (l, r) -> Expression.ushr(l, r)); + break; + case Opcodes.IAND: + binOperatorIns(type("I"), (l, r) -> Expression.and(l, r)); + break; + case Opcodes.LAND: + binOperatorIns(type("J"), (l, r) -> Expression.and(l, r)); + break; + case Opcodes.IOR: + binOperatorIns(type("I"), (l, r) -> Expression.or(l, r)); + break; + case Opcodes.LOR: + binOperatorIns(type("J"), (l, r) -> Expression.or(l, r)); + break; + case Opcodes.IXOR: + binOperatorIns(type("I"), (l, r) -> Expression.xor(l, r)); + break; + case Opcodes.LXOR: + binOperatorIns(type("J"), (l, r) -> Expression.xor(l, r)); + break; + case Opcodes.I2L: + simpleCastIns(type("J")); + break; + case Opcodes.I2F: + simpleCastIns(type("F")); + break; + case Opcodes.I2D: + simpleCastIns(type("D")); + break; + case Opcodes.L2I: + simpleCastIns(type("I")); + break; + case Opcodes.L2F: + simpleCastIns(type("F")); + break; + case Opcodes.L2D: + simpleCastIns(type("D")); + break; + case Opcodes.F2I: + simpleCastIns(type("I")); + break; + case Opcodes.F2L: + simpleCastIns(type("J")); + break; + case Opcodes.F2D: + simpleCastIns(type("D")); + break; + case Opcodes.D2I: + simpleCastIns(type("I")); + break; + case Opcodes.D2L: + simpleCastIns(type("J")); + break; + case Opcodes.D2F: + simpleCastIns(type("F")); + break; + case Opcodes.I2B: + simpleCastIns(type("B")); + break; + case Opcodes.I2C: + simpleCastIns(type("C")); + break; + case Opcodes.I2S: + simpleCastIns(type("S")); + break; + case Opcodes.LCMP: + binOperatorIns(type("I"), (l, r) -> Expression.cmp(l, r)); + break; + case Opcodes.FCMPG: + binOperatorIns(type("I"), (l, r) -> Expression.cmpg(l, r)); + break; + case Opcodes.FCMPL: + binOperatorIns(type("I"), (l, r) -> Expression.cmpl(l, r)); + break; + case Opcodes.DCMPG: + binOperatorIns(type("I"), (l, r) -> Expression.cmpg(l, r)); + break; + case Opcodes.DCMPL: + binOperatorIns(type("I"), (l, r) -> Expression.cmpl(l, r)); + break; + case Opcodes.IRETURN: + returnIns(); + break; + case Opcodes.LRETURN: + returnIns(); + break; + case Opcodes.FRETURN: + returnIns(); + break; + case Opcodes.DRETURN: + returnIns(); + break; + case Opcodes.ARETURN: + returnIns(); + break; + case Opcodes.RETURN: + returnVoidIns(); + break; + case Opcodes.ARRAYLENGTH: + arrayLengthIns(); + break; + case Opcodes.ATHROW: + throwIns(); + break; + case Opcodes.MONITORENTER: + monitorEnterIns(); + break; + case Opcodes.MONITOREXIT: + monitorExitIns(); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } super.visitInsn(opcode); } /* - * Visit a local variable instructions. + * Visit a local variable instructions. * * (non-Javadoc) + * * @see org.objectweb.asm.MethodVisitor#visitVarInsn(int, int) */ @Override public void visitVarInsn(int opcode, int var) { switch (opcode) { - case Opcodes.ILOAD : loadIns(var); break; - case Opcodes.LLOAD : loadIns(var); break; - case Opcodes.FLOAD : loadIns(var); break; - case Opcodes.DLOAD : loadIns(var); break; - case Opcodes.ALOAD : loadIns(var); break; - case Opcodes.ISTORE: storeIns(var); break; - case Opcodes.LSTORE: storeIns(var); break; - case Opcodes.FSTORE: storeIns(var); break; - case Opcodes.DSTORE: storeIns(var); break; - case Opcodes.ASTORE: storeIns(var); break; - case Opcodes.RET : retIns(var); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + case Opcodes.ILOAD: + loadIns(var); + break; + case Opcodes.LLOAD: + loadIns(var); + break; + case Opcodes.FLOAD: + loadIns(var); + break; + case Opcodes.DLOAD: + loadIns(var); + break; + case Opcodes.ALOAD: + loadIns(var); + break; + case Opcodes.ISTORE: + storeIns(var); + break; + case Opcodes.LSTORE: + storeIns(var); + break; + case Opcodes.FSTORE: + storeIns(var); + break; + case Opcodes.DSTORE: + storeIns(var); + break; + case Opcodes.ASTORE: + storeIns(var); + break; + case Opcodes.RET: + retIns(var); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } super.visitVarInsn(opcode, var); } - + /* - * Visit a type instruction. + * Visit a type instruction. * * (non-Javadoc) + * * @see org.objectweb.asm.MethodVisitor#visitTypeInsn(int, java.lang.String) */ @Override public void visitTypeInsn(int opcode, String type) { - switch(opcode) { - case Opcodes.NEW : newInstanceIns(objectConstructor(type.replace("/", "."))); break; - case Opcodes.ANEWARRAY : aNewArrayIns(type(type)); break; - case Opcodes.CHECKCAST : simpleCastIns(type(type)); break; - case Opcodes.INSTANCEOF : instanceOfIns(type(type)); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + switch (opcode) { + case Opcodes.NEW: + newInstanceIns(objectConstructor(type.replace("/", "."))); + break; + case Opcodes.ANEWARRAY: + aNewArrayIns(type(type)); + break; + case Opcodes.CHECKCAST: + simpleCastIns(type(type)); + break; + case Opcodes.INSTANCEOF: + instanceOfIns(type(type)); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } super.visitTypeInsn(opcode, type); } - - @Override public void visitIntInsn(int opcode, int operand) { - switch(opcode) { - case Opcodes.BIPUSH : pushConstantValue(type("I"), Immediate.iValue(Value.intValue(operand))); break; - case Opcodes.SIPUSH : pushConstantValue(type("I"), Immediate.iValue(Value.intValue(operand))); break; - case Opcodes.NEWARRAY : createNewArrayIns(operand); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + switch (opcode) { + case Opcodes.BIPUSH: + pushConstantValue(type("I"), Immediate.iValue(Value.intValue(operand))); + break; + case Opcodes.SIPUSH: + pushConstantValue(type("I"), Immediate.iValue(Value.intValue(operand))); + break; + case Opcodes.NEWARRAY: + createNewArrayIns(operand); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } super.visitIntInsn(opcode, operand); } @Override - public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterfaceInvoke) { - switch(opcode) { - case Opcodes.INVOKEVIRTUAL : invokeMethodIns(owner, name, descriptor, false, (r, s, args) -> InvokeExp.virtualInvoke(r, s, args)); break; - case Opcodes.INVOKESPECIAL : invokeMethodIns(owner, name, descriptor, false, (r, s, args) -> InvokeExp.specialInvoke(r, s, args)); break; - case Opcodes.INVOKESTATIC : invokeMethodIns(owner, name, descriptor, true, (r, s, args) -> InvokeExp.staticMethodInvoke(s, args)); break; - case Opcodes.INVOKEINTERFACE : invokeMethodIns(owner, name, descriptor, false, (r, s, args) -> InvokeExp.interfaceInvoke(r, s, args)); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + public void visitMethodInsn(int opcode, String owner, String name, String descriptor, + boolean isInterfaceInvoke) { + switch (opcode) { + case Opcodes.INVOKEVIRTUAL: + invokeMethodIns(owner, name, descriptor, false, (r, s, args) -> InvokeExp.virtualInvoke(r, s, args)); + break; + case Opcodes.INVOKESPECIAL: + invokeMethodIns(owner, name, descriptor, false, (r, s, args) -> InvokeExp.specialInvoke(r, s, args)); + break; + case Opcodes.INVOKESTATIC: + invokeMethodIns(owner, name, descriptor, true, (r, s, args) -> InvokeExp.staticMethodInvoke(s, args)); + break; + case Opcodes.INVOKEINTERFACE: + invokeMethodIns(owner, name, descriptor, false, (r, s, args) -> InvokeExp.interfaceInvoke(r, s, args)); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } super.visitMethodInsn(opcode, owner, name, descriptor, isInterfaceInvoke); } - - /* - * This is really tough. - * - * The implementation here is based on the - * Eric Bodden's paper published at SOAP 2012. - * InvokeDynamic support in Soot + + /* + * This is really tough. + * + * The implementation here is based on the Eric Bodden's paper published at SOAP + * 2012. InvokeDynamic support in Soot */ @Override - public void visitInvokeDynamicInsn(String name, String descriptor, Handle bsmh, Object... bootstrapMethodArguments) { + public void visitInvokeDynamicInsn(String name, String descriptor, Handle bsmh, + Object... bootstrapMethodArguments) { List bootstrapArgs = new ArrayList<>(); MethodSignature bootstrapMethod = methodSignature(bsmh); - - for(Object arg: bootstrapMethodArguments) { + + for (Object arg : bootstrapMethodArguments) { bootstrapArgs.add(Immediate.iValue(toJimpleTypedValue(arg).getSecond())); } - + Type methodType = methodReturnType(descriptor); List argTypes = methodArgumentTypes(descriptor); - - MethodSignature method = MethodSignature.builder() - .className(INVOKE_DYNAMIC_FAKE_CLASS) - .returnType(methodType) - .methodName(name) - .formals(argTypes) - .build(); - + + MethodSignature method = MethodSignature.builder().className(INVOKE_DYNAMIC_FAKE_CLASS) + .returnType(methodType).methodName(name).formals(argTypes).build(); + List args = new ArrayList<>(); - - for(int i = 0; i < argTypes.size(); i++) { - args.add(0, operandStack.pop().immediate); + + for (int i = 0; i < argTypes.size(); i++) { + args.add(0, pop().immediate); } - + InvokeExp exp = InvokeExp.dynamicInvoke(bootstrapMethod, bootstrapArgs, method, args); - - instructions.add(Statement.invokeStmt(exp)); + + addInstruction(Statement.invokeStmt(exp)); super.visitInvokeDynamicInsn(name, descriptor, bsmh, bootstrapMethodArguments); } - - + @Override public void visitLdcInsn(Object value) { - operandStack.push(new Operand(toJimpleTypedValue(value))); - + pushOperand(new Operand(toJimpleTypedValue(value))); + super.visitLdcInsn(value); } - @Override public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - Immediate key = operandStack.pop().immediate; - + Immediate key = pop().immediate; + List caseStmts = new ArrayList<>(); - - for(int i = 0; i < keys.length; i++) { + + for (int i = 0; i < keys.length; i++) { caseStmts.add(CaseStmt.caseOption(keys[i], labels[i].toString())); } - - if(dflt != null) { + + if (dflt != null) { caseStmts.add(CaseStmt.defaultOption(dflt.toString())); } - - instructions.add(Statement.lookupSwitch(key, caseStmts)); + + addInstruction(Statement.lookupSwitch(key, caseStmts)); super.visitLookupSwitchInsn(dflt, keys, labels); } - + @Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { - Immediate key = operandStack.pop().immediate; + Immediate key = pop().immediate; List caseStmts = new ArrayList<>(); - - for(Label label : labels) { + + for (Label label : labels) { caseStmts.add(CaseStmt.caseOption(label.getOffset(), label.toString())); } - - if(dflt != null) { + + if (dflt != null) { caseStmts.add(CaseStmt.defaultOption(dflt.toString())); } - instructions.add(Statement.tableSwitch(key, min, max, caseStmts)); + addInstruction(Statement.tableSwitch(key, min, max, caseStmts)); super.visitTableSwitchInsn(min, max, dflt, labels); } - + @Override public void visitJumpInsn(int opcode, Label label) { - if(opcode == Opcodes.GOTO) { - instructions.add(Statement.gotoStmt(label.toString())); - } - else if(opcode == Opcodes.JSR) { - throw RuntimeExceptionFactory.illegalArgument(vf.string("unsupported instruction JSR" + opcode), null, null); - } - else { - Expression exp = null; - Immediate first = operandStack.pop().immediate; + if (opcode == Opcodes.GOTO) { + addInstruction(Statement.gotoStmt(label.toString())); + } else if (opcode == Opcodes.JSR) { + throw RuntimeExceptionFactory.illegalArgument(vf.string("unsupported instruction JSR" + opcode), null, + null); + } else { + Expression exp = null; + Immediate first = pop().immediate; Immediate second = Immediate.iValue(Value.intValue(0)); - switch(opcode) { - case Opcodes.IFEQ: exp = Expression.cmpeq(first, second); break; - case Opcodes.IFNE: exp = Expression.cmpne(first, second); break; - case Opcodes.IFLT: exp = Expression.cmplt(first, second); break; - case Opcodes.IFLE: exp = Expression.cmple(first, second); break; - case Opcodes.IFGT: exp = Expression.cmpgt(first, second); break; - case Opcodes.IFGE: exp = Expression.cmpge(first, second); break; - case Opcodes.IF_ICMPEQ: second = operandStack.pop().immediate; exp = Expression.cmpeq(second, first); break; - case Opcodes.IF_ICMPNE: second = operandStack.pop().immediate; exp = Expression.cmpne(second, first); break; - case Opcodes.IF_ICMPLT: second = operandStack.pop().immediate; exp = Expression.cmplt(second, first); break; - case Opcodes.IF_ICMPGE: second = operandStack.pop().immediate; exp = Expression.cmpge(second, first); break; - case Opcodes.IF_ICMPGT: second = operandStack.pop().immediate; exp = Expression.cmpgt(second, first); break; - case Opcodes.IF_ICMPLE: second = operandStack.pop().immediate; exp = Expression.cmple(second, first); break; - case Opcodes.IF_ACMPEQ: second = operandStack.pop().immediate; exp = Expression.cmpeq(second, first); break; - case Opcodes.IF_ACMPNE: second = operandStack.pop().immediate; exp = Expression.cmpne(second, first); break; - case Opcodes.IFNULL: exp = Expression.isNull(first); break; - case Opcodes.IFNONNULL: exp = Expression.isNotNull(first); break; - default: throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); + switch (opcode) { + case Opcodes.IFEQ: + exp = Expression.cmpeq(first, second); + break; + case Opcodes.IFNE: + exp = Expression.cmpne(first, second); + break; + case Opcodes.IFLT: + exp = Expression.cmplt(first, second); + break; + case Opcodes.IFLE: + exp = Expression.cmple(first, second); + break; + case Opcodes.IFGT: + exp = Expression.cmpgt(first, second); + break; + case Opcodes.IFGE: + exp = Expression.cmpge(first, second); + break; + case Opcodes.IF_ICMPEQ: + second = pop().immediate; + exp = Expression.cmpeq(second, first); + break; + case Opcodes.IF_ICMPNE: + second = pop().immediate; + exp = Expression.cmpne(second, first); + break; + case Opcodes.IF_ICMPLT: + second = pop().immediate; + exp = Expression.cmplt(second, first); + break; + case Opcodes.IF_ICMPGE: + second = pop().immediate; + exp = Expression.cmpge(second, first); + break; + case Opcodes.IF_ICMPGT: + second = pop().immediate; + exp = Expression.cmpgt(second, first); + break; + case Opcodes.IF_ICMPLE: + second = pop().immediate; + exp = Expression.cmple(second, first); + break; + case Opcodes.IF_ACMPEQ: + second = pop().immediate; + exp = Expression.cmpeq(second, first); + break; + case Opcodes.IF_ACMPNE: + second = pop().immediate; + exp = Expression.cmpne(second, first); + break; + case Opcodes.IFNULL: + exp = Expression.isNull(first); + break; + case Opcodes.IFNONNULL: + exp = Expression.isNotNull(first); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, + null); } - instructions.add(Statement.ifStmt(exp, label.toString())); + addInstruction(Statement.ifStmt(exp, label.toString())); } referencedLabels.add(label.toString()); super.visitJumpInsn(opcode, label); } - - //IFNULL or IFNONNULL - - // auxiliarly methods. - private void invokeMethodIns(String owner, String name, String descriptor, boolean isStatic, InvokeExpressionFactory factory) { + // IFNULL or IFNONNULL + + // auxiliarly methods. + + private void invokeMethodIns(String owner, String name, String descriptor, boolean isStatic, + InvokeExpressionFactory factory) { MethodSignature signature = methodSignature(owner.replace("/", "."), name, descriptor); List args = new ArrayList<>(); - - for(int i = 0; i < signature.formals.size(); i++) { - args.add(0, operandStack.pop().immediate); - } - - InvokeExp exp = null; - - if(! isStatic) { - String reference = ((Immediate.c_local)operandStack.pop().immediate).localName; - exp = factory.createInvokeExpression(reference, signature, args); + + for (int i = 0; i < signature.formals.size(); i++) { + args.add(0, pop().immediate); } - else { + + InvokeExp exp = null; + + if (!isStatic) { + String reference = ((Immediate.c_local) pop().immediate).localName; + exp = factory.createInvokeExpression(reference, signature, args); + } else { exp = factory.createInvokeExpression(null, signature, args); } - - if(signature.returnType.equals(Type.TVoid())) { - instructions.add(Statement.invokeStmt(exp)); - } - else { + + if (signature.returnType.equals(Type.TVoid())) { + addInstruction(Statement.invokeStmt(exp)); + } else { LocalVariableDeclaration local = createLocal(signature.returnType); - instructions.add(assignmentStmt(Variable.localVariable(local.local), Expression.invokeExp(exp))); - operandStack.push(new Operand(local)); + addInstruction(assignmentStmt(Variable.localVariable(local.local), Expression.invokeExp(exp))); + pushOperand(new Operand(local)); } } - private LocalVariableDeclaration findLocalVariable(int idx) { for (LocalVariableNode node : localVariables.keySet()) { if (node.index == idx) { return localVariables.get(node); } } - // the following code deals with the situations - // where the source code has not been compiled with - // debugging information + // the following code deals with the situations + // where the source code has not been compiled with + // debugging information // // throw new RuntimeException("local variable not found"); - String local = LOCAL_VARIABLE_PARAMETER_PREFIX + idx; - + String local = LOCAL_VARIABLE_PARAMETER_PREFIX + idx; + LocalVariableDeclaration var = new LocalVariableDeclaration(Type.TUnknown(), local); - LocalVariableNode node = new LocalVariableNode(local, null, null, null, null, idx); - localVariables.put(node, var); - - return var; + LocalVariableNode node = new LocalVariableNode(local, null, null, null, null, idx); + localVariables.put(node, var); + + return var; } - + /* - * Load a local variable into the top of the - * operand stack. + * Load a local variable into the top of the operand stack. */ private void loadIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); - operandStack.push(new Operand(local)); + pushOperand(new Operand(local)); } /* @@ -749,436 +1060,423 @@ private void loadIns(int var) { */ private void storeIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); - Immediate immediate = operandStack.pop().immediate; - instructions.add(assignmentStmt(Variable.localVariable(local.local), Expression.immediate(immediate))); + Immediate immediate = pop().immediate; + addInstruction(assignmentStmt(Variable.localVariable(local.local), Expression.immediate(immediate))); } /* - * Return from a subroutine. Not really clear the corresponding - * Java code. It seems to me a more internal instruction from - * the JVM. It is different from a return void call, for instance. + * Return from a subroutine. Not really clear the corresponding Java code. It + * seems to me a more internal instruction from the JVM. It is different from a + * return void call, for instance. */ private void retIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); - instructions.add(Statement.retStmt(Immediate.local(local.local))); + addInstruction(Statement.retStmt(Immediate.local(local.local))); } - + private void newInstanceIns(Type type) { LocalVariableDeclaration newLocal = createLocal(type); - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newInstance(type))); - operandStack.push(new Operand(newLocal)); + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newInstance(type))); + pushOperand(new Operand(newLocal)); } - + private void aNewArrayIns(Type type) { - Operand operand = operandStack.pop(); + Operand operand = pop(); LocalVariableDeclaration newLocal = createLocal(Type.TArray(type)); - c_iValue value = (Immediate.c_iValue)operand.immediate; - + c_iValue value = (Immediate.c_iValue) operand.immediate; + assert (value.v instanceof Value.c_intValue); - - Integer size = ((Value.c_intValue)value.v).iv; - + + Integer size = ((Value.c_intValue) value.v).iv; + List dims = new ArrayList<>(); - dims.add(ArrayDescriptor.fixedSize(size)); + dims.add(ArrayDescriptor.fixedSize(size)); - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newArray(type, dims))); - operandStack.push(new Operand(newLocal)); + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newArray(type, dims))); + pushOperand(new Operand(newLocal)); } + /* - * Add a nop instruction + * Add a nop instruction */ private void nopIns() { - instructions.add(Statement.nop()); + addInstruction(Statement.nop()); } /* - * Load a null value into the top of the - * operand stack. + * Load a null value into the top of the operand stack. */ private void acconstNullIns() { - operandStack.push(new Operand(Type.TNull(), Immediate.iValue(Value.nullValue()))); + pushOperand(new Operand(Type.TNull(), Immediate.iValue(Value.nullValue()))); } /* - * Load an int const into the top of the - * operand stack. + * Load an int const into the top of the operand stack. */ private void loadIntConstIns(int value, String descriptor) { - operandStack.push(new Operand(type(descriptor), Immediate.iValue(Value.intValue(value)))); + pushOperand(new Operand(type(descriptor), Immediate.iValue(Value.intValue(value)))); } /* - * Load a float const into the top of the - * operand stack. + * Load a float const into the top of the operand stack. */ private void loadRealConstIns(float value, String descriptor) { - operandStack.push(new Operand(type(descriptor), Immediate.iValue(Value.floatValue(value)))); + pushOperand(new Operand(type(descriptor), Immediate.iValue(Value.floatValue(value)))); } - /* * Neg instruction (INEG, LNEG, FNEG, DNEG) */ private void negIns(Type type) { - Operand operand = operandStack.pop(); - + Operand operand = pop(); + LocalVariableDeclaration newLocal = createLocal(type); - + Expression expression = Expression.neg(operand.immediate); - - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), expression)); - - operandStack.push(new Operand(newLocal)); + + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), expression)); + + pushOperand(new Operand(newLocal)); } - + /* - * Instructions supporting binarya operations. + * Instructions supporting binarya operations. */ private void binOperatorIns(Type type, BinExpressionFactory factory) { - Operand rhs = operandStack.pop(); - Operand lhs = operandStack.pop(); + Operand rhs = pop(); + Operand lhs = pop(); LocalVariableDeclaration newLocal = createLocal(type); - + Expression expression = factory.createExpression(lhs.immediate, rhs.immediate); - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), expression)); + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), expression)); - operandStack.push(new Operand(newLocal)); + pushOperand(new Operand(newLocal)); } - + private void simpleCastIns(Type targetType) { - Operand operand = operandStack.pop(); + Operand operand = pop(); LocalVariableDeclaration newLocal = createLocal(targetType); - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.cast(targetType, operand.immediate))); - operandStack.push(new Operand(newLocal)); + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), + Expression.cast(targetType, operand.immediate))); + pushOperand(new Operand(newLocal)); } - + private void instanceOfIns(Type type) { - Operand operand = operandStack.pop(); + Operand operand = pop(); LocalVariableDeclaration newLocal = createLocal(Type.TBoolean()); - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.instanceOf(type, operand.immediate))); - operandStack.push(new Operand(newLocal)); + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), + Expression.instanceOf(type, operand.immediate))); + pushOperand(new Operand(newLocal)); } - + private void returnIns() { - Operand operand = operandStack.pop(); - instructions.add(Statement.returnStmt(operand.immediate)); - // TODO: perhaps we should call an exit monitor here. - operandStack.empty(); + Operand operand = pop(); + addInstruction(Statement.returnStmt(operand.immediate)); + // TODO: perhaps we should call an exit monitor here. + notifyReturn(); } - + private void returnVoidIns() { - instructions.add(Statement.returnEmptyStmt()); - // TODO: perhaps we should call an exit monitor here. - operandStack.empty(); + addInstruction(Statement.returnEmptyStmt()); + // TODO: perhaps we should call an exit monitor here. + notifyReturn(); } - + private void arrayLengthIns() { - Operand arrayRef = operandStack.pop(); + Operand arrayRef = pop(); LocalVariableDeclaration newLocal = createLocal("I"); - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.lengthOf(arrayRef.immediate))); - operandStack.push(new Operand(newLocal)); + addInstruction( + assignmentStmt(Variable.localVariable(newLocal.local), Expression.lengthOf(arrayRef.immediate))); + pushOperand(new Operand(newLocal)); } - + private void throwIns() { - Operand reference = operandStack.pop(); - instructions.add(Statement.throwStmt(reference.immediate)); - operandStack.empty(); - operandStack.push(reference); + Operand reference = pop(); + addInstruction(Statement.throwStmt(reference.immediate)); + notifyReturn(); + pushOperand(reference); } - + private void monitorEnterIns() { - Operand reference = operandStack.pop(); - instructions.add(Statement.enterMonitor(reference.immediate)); + Operand reference = pop(); + addInstruction(Statement.enterMonitor(reference.immediate)); } - + private void monitorExitIns() { - Operand reference = operandStack.pop(); - instructions.add(Statement.exitMonitor(reference.immediate)); + Operand reference = pop(); + addInstruction(Statement.exitMonitor(reference.immediate)); } - /* - * Update the top of the operand stack with - * the value of a specific indexed element of an - * array. The index and the array's reference - * are popped up from the stack. + * Update the top of the operand stack with the value of a specific indexed + * element of an array. The index and the array's reference are popped up from + * the stack. */ private void arraySubscriptIns() { - Operand idx = operandStack.pop(); - Operand ref = operandStack.pop(); - + Operand idx = pop(); + Operand ref = pop(); + Type baseType = ref.type; - - if(baseType instanceof Type.c_TArray) { - baseType = ((Type.c_TArray)baseType).baseType; + + if (baseType instanceof Type.c_TArray) { + baseType = ((Type.c_TArray) baseType).baseType; } - - LocalVariableDeclaration newLocal =createLocal(baseType); - - instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), newArraySubscript(((Immediate.c_local)ref.immediate).localName,idx.immediate))); - - operandStack.push(new Operand(newLocal)); + + LocalVariableDeclaration newLocal = createLocal(baseType); + + addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), + newArraySubscript(((Immediate.c_local) ref.immediate).localName, idx.immediate))); + + pushOperand(new Operand(newLocal)); } - + /* - * Updates a position of an array with a - * value. The stack must be with the values: + * Updates a position of an array with a value. The stack must be with the + * values: + * + * [ value ] [ idx ] [ array ] [ ... ] _________ * - * [ value ] - * [ idx ] - * [ array ] - * [ ... ] - * _________ - * - * After popping value, idx, and array, - * no value is introduced into the stack. + * After popping value, idx, and array, no value is introduced into the stack. */ private void storeIntoArrayIns() { - Immediate value = operandStack.pop().immediate; - Immediate idx = operandStack.pop().immediate; - Immediate arrayRef = operandStack.pop().immediate; - - Variable var = Variable.arrayRef(((Immediate.c_local)arrayRef).localName, idx); - - instructions.add(assignmentStmt(var, Expression.immediate(value))); + Immediate value = pop().immediate; + Immediate idx = pop().immediate; + Immediate arrayRef = pop().immediate; + + Variable var = Variable.arrayRef(((Immediate.c_local) arrayRef).localName, idx); + + addInstruction(assignmentStmt(var, Expression.immediate(value))); } - + /* - * Removes an operand from the stack. + * Removes an operand from the stack. */ private void popIns() { - operandStack.pop(); + pop(); } - + /* - * Removes either one or two operand from the - * top of the stack. If the type of the first - * operand is either a long or a double, it - * removes just one operand. + * Removes either one or two operand from the top of the stack. If the type of + * the first operand is either a long or a double, it removes just one operand. */ private void pop2Ins() { - Operand value = operandStack.pop(); - - if(allCategory1(value.type)) { - operandStack.pop(); + Operand value = pop(); + + if (allCategory1(value.type)) { + pop(); } } - + /* * Duplicate the top operand stack value */ private void dupIns() { - Operand value = operandStack.pop(); - - operandStack.push(value); - operandStack.push(value); + Operand value = pop(); + + pushOperand(value); + pushOperand(value); } - + /* - * Duplicate the top operand stack value and insert - * the copy two values down. + * Duplicate the top operand stack value and insert the copy two values down. */ private void dupX1Ins() { - assert operandStack.size() >= 2; - - Operand value1 = operandStack.pop(); - Operand value2 = operandStack.pop(); - - operandStack.push(value1); - operandStack.push(value2); - operandStack.push(value1); + assert sizeOfOperandStack() >= 2; + + Operand value1 = pop(); + Operand value2 = pop(); + + pushOperand(value1); + pushOperand(value2); + pushOperand(value1); } - + /* - * Duplicate the top operand stack value and insert - * the copy two or three values down. + * Duplicate the top operand stack value and insert the copy two or three values + * down. */ private void dupX2Ins() { - assert operandStack.size() >= 2; - - Operand value1 = operandStack.pop(); - - if(allCategory1(value1.type)) { - Operand value2 = operandStack.pop(); - Operand value3 = operandStack.pop(); - operandStack.push(value1); - operandStack.push(value3); - operandStack.push(value2); - operandStack.push(value1); - } - else { - Operand value2 = operandStack.pop(); - operandStack.push(value1); - operandStack.push(value2); - operandStack.push(value1); + assert sizeOfOperandStack() >= 2; + + Operand value1 = pop(); + + if (allCategory1(value1.type)) { + Operand value2 = pop(); + Operand value3 = pop(); + pushOperand(value1); + pushOperand(value3); + pushOperand(value2); + pushOperand(value1); + } else { + Operand value2 = pop(); + pushOperand(value1); + pushOperand(value2); + pushOperand(value1); } } - + /* - * Duplicate the top one or two operand stack values. - * It duplicates the two top operand stack values (v1 and v2) - * if both have types of category1. Otherwise, it - * duplicates just the first value. + * Duplicate the top one or two operand stack values. It duplicates the two top + * operand stack values (v1 and v2) if both have types of category1. Otherwise, + * it duplicates just the first value. */ private void dup2Ins() { - assert operandStack.size() >= 2; - - Operand value1 = operandStack.pop(); - Operand value2 = operandStack.pop(); - - if(allCategory1(value1.type, value2.type)) { - operandStack.push(value2); - operandStack.push(value1); - operandStack.push(value2); - operandStack.push(value1); - } - else { - operandStack.push(value2); - operandStack.push(value1); - operandStack.push(value1); + assert sizeOfOperandStack() >= 2; + + Operand value1 = pop(); + Operand value2 = pop(); + + if (allCategory1(value1.type, value2.type)) { + pushOperand(value2); + pushOperand(value1); + pushOperand(value2); + pushOperand(value1); + } else { + pushOperand(value2); + pushOperand(value1); + pushOperand(value1); } } - + /* - * Duplicate the top one or two operand stack values and - * insert two or three values down, depending on the - * type category of the values. + * Duplicate the top one or two operand stack values and insert two or three + * values down, depending on the type category of the values. */ private void dup2X1Ins() { - assert operandStack.size() >= 3; - - Operand value1 = operandStack.pop(); - Operand value2 = operandStack.pop(); - Operand value3 = operandStack.pop(); - - if(allCategory1(value1.type, value2.type, value3.type)) { - operandStack.push(value2); - operandStack.push(value1); - operandStack.push(value3); - operandStack.push(value2); - operandStack.push(value1); - } - else if((allCategory2(value1.type)) && allCategory1(value2.type)){ - operandStack.push(value3); - operandStack.push(value1); - operandStack.push(value2); - operandStack.push(value1); + assert sizeOfOperandStack() >= 3; + + Operand value1 = pop(); + Operand value2 = pop(); + Operand value3 = pop(); + + if (allCategory1(value1.type, value2.type, value3.type)) { + pushOperand(value2); + pushOperand(value1); + pushOperand(value3); + pushOperand(value2); + pushOperand(value1); + } else if ((allCategory2(value1.type)) && allCategory1(value2.type)) { + pushOperand(value3); + pushOperand(value1); + pushOperand(value2); + pushOperand(value1); } } /* - * Duplicate the top one or two operand stack values and insert two, three, or four values down + * Duplicate the top one or two operand stack values and insert two, three, or + * four values down */ private void dup2X2Ins() { - assert operandStack.size() >= 4; - - Operand value1 = operandStack.pop(); - Operand value2 = operandStack.pop(); - Operand value3 = operandStack.pop(); - Operand value4 = operandStack.pop(); - - if(allCategory1(value1.type, value2.type, value3.type, value4.type)) { - operandStack.push(value2); - operandStack.push(value1); - operandStack.push(value4); - operandStack.push(value3); - operandStack.push(value2); - operandStack.push(value1); - } - else if((allCategory2(value1.type)) && allCategory1(value2.type, value3.type)) { - operandStack.push(value4); - operandStack.push(value1); - operandStack.push(value3); - operandStack.push(value2); - operandStack.push(value1); - } - else if(allCategory1(value1.type, value2.type) && (allCategory2(value3.type))) { - operandStack.push(value4); - operandStack.push(value2); - operandStack.push(value1); - operandStack.push(value3); - operandStack.push(value2); - operandStack.push(value1); - } - else if((!allCategory2(value1.type, value2.type))) { - operandStack.push(value4); - operandStack.push(value3); - operandStack.push(value1); - operandStack.push(value2); - operandStack.push(value1); + assert sizeOfOperandStack() >= 4; + + Operand value1 = pop(); + Operand value2 = pop(); + Operand value3 = pop(); + Operand value4 = pop(); + + if (allCategory1(value1.type, value2.type, value3.type, value4.type)) { + pushOperand(value2); + pushOperand(value1); + pushOperand(value4); + pushOperand(value3); + pushOperand(value2); + pushOperand(value1); + } else if ((allCategory2(value1.type)) && allCategory1(value2.type, value3.type)) { + pushOperand(value4); + pushOperand(value1); + pushOperand(value3); + pushOperand(value2); + pushOperand(value1); + } else if (allCategory1(value1.type, value2.type) && (allCategory2(value3.type))) { + pushOperand(value4); + pushOperand(value2); + pushOperand(value1); + pushOperand(value3); + pushOperand(value2); + pushOperand(value1); + } else if ((!allCategory2(value1.type, value2.type))) { + pushOperand(value4); + pushOperand(value3); + pushOperand(value1); + pushOperand(value2); + pushOperand(value1); } - + } - + private void swapIns() { - assert operandStack.size() >= 2; - - Operand value1 = operandStack.pop(); - Operand value2 = operandStack.pop(); - - operandStack.push(value1); - operandStack.push(value2); + assert sizeOfOperandStack() >= 2; + + Operand value1 = pop(); + Operand value2 = pop(); + + pushOperand(value1); + pushOperand(value2); } - + /* - * Load the value of a static field into the top - * of the operand stack. + * Load the value of a static field into the top of the operand stack. + * + * @param owner the field's owner class. * - * @param owner the field's owner class. - * @param field the name of the field. - * @param descriptor use to compute the field's type. + * @param field the name of the field. + * + * @param descriptor use to compute the field's type. */ private void getStaticIns(String owner, String field, String descriptor) { LocalVariableDeclaration newLocal = createLocal(descriptor); Type fieldType = type(descriptor); Expression fieldRef = Expression.fieldRef(owner.replace("/", "."), fieldType, field); - - instructions.add(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); - operandStack.push(new Operand(newLocal)); + addInstruction(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); + + pushOperand(new Operand(newLocal)); } - + private void putStaticIns(String owner, String field, String descriptor) { - Operand value = operandStack.pop(); + Operand value = pop(); FieldSignature signature = FieldSignature.fieldSignature(owner, type(descriptor), field); - instructions.add(assignmentStmt(Variable.staticFieldRef(signature), Expression.immediate(value.immediate))); + addInstruction(assignmentStmt(Variable.staticFieldRef(signature), Expression.immediate(value.immediate))); } - + private void putFieldIns(String owner, String field, String descriptor) { - Operand value = operandStack.pop(); - Operand operand = operandStack.pop(); - - String reference = ((Immediate.c_local)operand.immediate).localName; - + Operand value = pop(); + Operand operand = pop(); + + String reference = ((Immediate.c_local) operand.immediate).localName; + FieldSignature signature = FieldSignature.fieldSignature(owner, type(descriptor), field); - - instructions.add(assignmentStmt(Variable.fieldRef(reference, signature), Expression.immediate(value.immediate))); + + addInstruction( + assignmentStmt(Variable.fieldRef(reference, signature), Expression.immediate(value.immediate))); } /* - * Load the value of an instance field into the top - * of the operand stack. The instance object is popped - * from the stack. + * Load the value of an instance field into the top of the operand stack. The + * instance object is popped from the stack. + * + * @param owner the field's owner class. + * + * @param field the name of the field. * - * @param owner the field's owner class. - * @param field the name of the field. - * @param descriptor use to compute the field's type. + * @param descriptor use to compute the field's type. */ private void getFieldIns(String owner, String field, String descriptor) { - Immediate instance = operandStack.pop().immediate; - + Immediate instance = pop().immediate; + LocalVariableDeclaration newLocal = createLocal(descriptor); - + Type fieldType = type(descriptor); - - Expression fieldRef = Expression.localFieldRef(((Immediate.c_local)instance).localName, - owner, fieldType, field); - - instructions.add(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); - - operandStack.push(new Operand(newLocal)); + + Expression fieldRef = Expression.localFieldRef(((Immediate.c_local) instance).localName, owner, fieldType, + field); + + addInstruction(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); + + pushOperand(new Operand(newLocal)); } private LocalVariableDeclaration createLocal(String descriptor) { @@ -1191,110 +1489,92 @@ private LocalVariableDeclaration createLocal(Type type) { auxiliarlyLocalVariables.add(local); return local; } - - private boolean allCategory1(Type ... types) { - for(Type t: types) { - if(t instanceof Type.c_TDouble || t instanceof Type.c_TLong) { + + private boolean allCategory1(Type... types) { + for (Type t : types) { + if (t instanceof Type.c_TDouble || t instanceof Type.c_TLong) { return false; } } - return true; + return true; } - - private boolean allCategory2(Type ... types) { - for(Type t: types) { - if(!(t instanceof Type.c_TDouble || t instanceof Type.c_TLong)) { + + private boolean allCategory2(Type... types) { + for (Type t : types) { + if (!(t instanceof Type.c_TDouble || t instanceof Type.c_TLong)) { return false; } } - return true; + return true; } - + private void pushConstantValue(Type type, Immediate immediate) { - operandStack.push(new Operand(type, immediate)); + pushOperand(new Operand(type, immediate)); } - + private void createNewArrayIns(int aType) { - Type type = null; - switch(aType) { - case 4 : type = type("Z"); break; - case 5 : type = type("C"); break; - case 6 : type = type("F"); break; - case 7 : type = type("D"); break; - case 8 : type = type("B"); break; - case 9 : type = type("S"); break; - case 10: type = type("I"); break; - case 11: type = type("J"); break; + Type type = null; + switch (aType) { + case 4: + type = type("Z"); + break; + case 5: + type = type("C"); + break; + case 6: + type = type("F"); + break; + case 7: + type = type("D"); + break; + case 8: + type = type("B"); + break; + case 9: + type = type("S"); + break; + case 10: + type = type("I"); + break; + case 11: + type = type("J"); + break; } aNewArrayIns(type); } - - public void initFormalArgs(boolean staticMethod, Type classType, boolean emptyLocalVariableTable, List formals) { - if(emptyLocalVariableTable) { - assert localVariables.isEmpty(); // we expect an empty list of local variables here. - if(!staticMethod) { - LocalVariableNode node = new LocalVariableNode(THIS_VARIABLE, classType.getBaseType(), null, null, null, 0); - localVariables.put(node, LocalVariableDeclaration.localVariableDeclaration(classType, LOCAL_NAME_FOR_IMPLICIT_PARAMETER)); + + public void initFormalArgs(boolean staticMethod, Type classType, boolean emptyLocalVariableTable, + List formals) { + if (emptyLocalVariableTable) { + assert localVariables.isEmpty(); // we expect an empty list of local variables here. + if (!staticMethod) { + LocalVariableNode node = new LocalVariableNode(THIS_VARIABLE, classType.getBaseType(), null, null, + null, 0); + localVariables.put(node, LocalVariableDeclaration.localVariableDeclaration(classType, + LOCAL_NAME_FOR_IMPLICIT_PARAMETER)); } - int idx = 1; - for(Type t: formals) { + int idx = 1; + for (Type t : formals) { String local = LOCAL_VARIABLE_PARAMETER_PREFIX + idx; LocalVariableNode node = new LocalVariableNode(local, t.getBaseType(), null, null, null, idx); localVariables.put(node, LocalVariableDeclaration.localVariableDeclaration(t, local)); idx++; } } - if(!staticMethod) { - instructions.add(Statement.identity(LOCAL_NAME_FOR_IMPLICIT_PARAMETER, IMPLICIT_PARAMETER_NAME, classType)); // init the implicit parameter - } - int idx = 0; - for(Type t: formals) { - instructions.add(Statement.identity(LOCAL_VARIABLE_PARAMETER_PREFIX + (idx +1), LOCAL_PARAMETER_PREFIX + idx, t)); - idx++; - } - } - - @Deprecated - public void clearUnusedLabelInstructions() { - List toRemove = new ArrayList<>(); - Map newLabels = new HashMap<>(); - - int count = 1; - - // compute the labels that are used in jump instructions (goto / if) - for(Statement s: instructions) { - if(s instanceof Statement.c_label) { - Statement.c_label labelIns = (Statement.c_label)s; - if(!referencedLabels.contains(labelIns.label)) { - toRemove.add(labelIns); - } - else { - newLabels.put(labelIns.label, count); - labelIns.label = String.format("label%d", count++); - } - } - } - - // remove unused labels ... - for(Statement s: toRemove) { - instructions.remove(s); + if (!staticMethod) { + addInstruction(Statement.identity(LOCAL_NAME_FOR_IMPLICIT_PARAMETER, IMPLICIT_PARAMETER_NAME, classType)); // init + // the + // implicit + // parameter } - - // update the references to the "user friendly" labels - for(Statement s: instructions) { - if(s instanceof Statement.c_gotoStmt) { - Statement.c_gotoStmt g = (Statement.c_gotoStmt)s; - g.target = newLabels.containsKey(g.target) ? String.format("label%d", newLabels.get(g.target)) : g.target; - } - else if(s instanceof Statement.c_ifStmt) { - Statement.c_ifStmt i = (Statement.c_ifStmt)s; - i.target = newLabels.containsKey(i.target) ? String.format("label%d", newLabels.get(i.target)) : i.target; - } + int idx = 0; + for (Type t : formals) { + addInstruction(Statement.identity(LOCAL_VARIABLE_PARAMETER_PREFIX + (idx + 1), + LOCAL_PARAMETER_PREFIX + idx, t)); + idx++; } } - + } - - - + } diff --git a/src/main/java/lang/jimple/internal/InstructionFlow.java b/src/main/java/lang/jimple/internal/InstructionFlow.java new file mode 100644 index 00000000..c8efa419 --- /dev/null +++ b/src/main/java/lang/jimple/internal/InstructionFlow.java @@ -0,0 +1,16 @@ +package lang.jimple.internal; + +import java.util.Collection; + +import lang.jimple.internal.generated.Statement; + +public interface InstructionFlow { + + public void push(Operand operand); + public Operand pop(); + public void addInstruction(Statement stmt); + public void clearOperandStack(); + public int sizeOfOperandStack(); + public Collection merge(); + +} diff --git a/src/main/java/lang/jimple/internal/JimpleObjectFactory.java b/src/main/java/lang/jimple/internal/JimpleObjectFactory.java index 75227762..a20e226e 100644 --- a/src/main/java/lang/jimple/internal/JimpleObjectFactory.java +++ b/src/main/java/lang/jimple/internal/JimpleObjectFactory.java @@ -3,16 +3,11 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import javax.swing.text.html.HTML.Tag; - import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; -import io.usethesource.vallang.io.binary.util.TaggedInt; -import lang.jimple.internal.Decompiler.InstructionSetVisitor.Operand; import lang.jimple.internal.generated.Expression; import lang.jimple.internal.generated.FieldSignature; import lang.jimple.internal.generated.Immediate; diff --git a/src/main/java/lang/jimple/internal/Operand.java b/src/main/java/lang/jimple/internal/Operand.java new file mode 100644 index 00000000..d12c8cce --- /dev/null +++ b/src/main/java/lang/jimple/internal/Operand.java @@ -0,0 +1,28 @@ +package lang.jimple.internal; + +import lang.jimple.internal.generated.Immediate; +import lang.jimple.internal.generated.LocalVariableDeclaration; +import lang.jimple.internal.generated.Type; +import lang.jimple.internal.generated.Value; +import lang.jimple.util.Pair; + +public class Operand { + + public Type type; + public Immediate immediate; + + Operand(Type type, Immediate immediate) { + this.type = type; + this.immediate = immediate; + } + + Operand(LocalVariableDeclaration localDeclaration) { + this.type = localDeclaration.varType; + this.immediate = Immediate.local(localDeclaration.local); + } + + Operand(Pair typedValue) { + this.type = typedValue.getFirst(); + this.immediate = Immediate.iValue(typedValue.getSecond()); + } +} \ No newline at end of file diff --git a/src/main/java/lang/jimple/internal/SingleInstructionFlow.java b/src/main/java/lang/jimple/internal/SingleInstructionFlow.java new file mode 100644 index 00000000..a57f8456 --- /dev/null +++ b/src/main/java/lang/jimple/internal/SingleInstructionFlow.java @@ -0,0 +1,46 @@ +package lang.jimple.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Stack; + +import lang.jimple.internal.generated.Statement; + +public class SingleInstructionFlow implements InstructionFlow { + + Stack operands; + List instructions; + + public SingleInstructionFlow() { + operands = new Stack<>(); + instructions = new ArrayList<>(); + } + + public void push(Operand operand) { + operands.push(operand); + } + + public Operand pop() { + return operands.pop(); + } + + public void addInstruction(Statement stmt) { + instructions.add(stmt); + } + + public void clearOperandStack() { + operands.clear(); + } + + @Override + public int sizeOfOperandStack() { + return operands.size(); + } + + @Override + public Collection merge() { + return new ArrayList<>(instructions); + } + +} diff --git a/src/main/java/lang/jimple/internal/generated/Statement.java b/src/main/java/lang/jimple/internal/generated/Statement.java index 32aea649..b60405d0 100644 --- a/src/main/java/lang/jimple/internal/generated/Statement.java +++ b/src/main/java/lang/jimple/internal/generated/Statement.java @@ -1,724 +1,690 @@ package lang.jimple.internal.generated; -import lang.jimple.internal.JimpleAbstractDataType; -import java.util.List; +import lang.jimple.internal.JimpleAbstractDataType; +import java.util.List; -import lombok.*; +import lombok.*; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IList; import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; - +import io.usethesource.vallang.IValueFactory; @EqualsAndHashCode public abstract class Statement extends JimpleAbstractDataType { - @Override - public String getBaseType() { - return "Statement"; - } - - - - public static Statement label(String label) { - return new c_label(label); - } - - public static Statement breakpoint() { - return new c_breakpoint(); - } - - public static Statement enterMonitor(Immediate immediate) { - return new c_enterMonitor(immediate); - } - - public static Statement exitMonitor(Immediate immediate) { - return new c_exitMonitor(immediate); - } - - public static Statement tableSwitch(Immediate immediate, Integer min, Integer max, List stmts) { - return new c_tableSwitch(immediate, min, max, stmts); - } - - public static Statement lookupSwitch(Immediate immediate, List stmts) { - return new c_lookupSwitch(immediate, stmts); - } - - public static Statement identity(String local, String identifier, Type idType) { - return new c_identity(local, identifier, idType); - } - - public static Statement identityNoType(String local, String identifier) { - return new c_identityNoType(local, identifier); - } - - public static Statement assign(Variable var, Expression expression) { - return new c_assign(var, expression); - } - - public static Statement ifStmt(Expression exp, String target) { - return new c_ifStmt(exp, target); - } - - public static Statement retEmptyStmt() { - return new c_retEmptyStmt(); - } - - public static Statement retStmt(Immediate immediate) { - return new c_retStmt(immediate); - } - - public static Statement returnEmptyStmt() { - return new c_returnEmptyStmt(); - } - - public static Statement returnStmt(Immediate immediate) { - return new c_returnStmt(immediate); - } - - public static Statement throwStmt(Immediate immediate) { - return new c_throwStmt(immediate); - } - - public static Statement invokeStmt(InvokeExp invokeExpression) { - return new c_invokeStmt(invokeExpression); - } - - public static Statement gotoStmt(String target) { - return new c_gotoStmt(target); - } - - public static Statement nop() { - return new c_nop(); - } - - - - @EqualsAndHashCode - public static class c_label extends Statement { - - public String label; - - - public c_label(String label) { - - this.label = label; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_label = vf.string(label); - - - return vf.constructor(getVallangConstructor() - - , iv_label - - ); - } - - @Override - public String getConstructor() { - return "label"; - } - } - - @EqualsAndHashCode - public static class c_breakpoint extends Statement { - - - public c_breakpoint() { - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - - return vf.constructor(getVallangConstructor() - - ); - } - - @Override - public String getConstructor() { - return "breakpoint"; - } - } - - @EqualsAndHashCode - public static class c_enterMonitor extends Statement { - - public Immediate immediate; - - - public c_enterMonitor(Immediate immediate) { - - this.immediate = immediate; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - ); - } - - @Override - public String getConstructor() { - return "enterMonitor"; - } - } - - @EqualsAndHashCode - public static class c_exitMonitor extends Statement { - - public Immediate immediate; - - - public c_exitMonitor(Immediate immediate) { - - this.immediate = immediate; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - ); - } - - @Override - public String getConstructor() { - return "exitMonitor"; - } - } - - @EqualsAndHashCode - public static class c_tableSwitch extends Statement { - - public Immediate immediate; - - public Integer min; - - public Integer max; - - public List stmts; - - - public c_tableSwitch(Immediate immediate, Integer min, Integer max, List stmts) { - - this.immediate = immediate; - - this.min = min; - - this.max = max; - - this.stmts = stmts; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - IValue iv_min = vf.integer(min); - - IValue iv_max = vf.integer(max); - - IList iv_stmts = vf.list(); - - for(CaseStmt v: stmts) { - iv_stmts = iv_stmts.append(v.createVallangInstance(vf)); - } - - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - , iv_min - - , iv_max - - , iv_stmts - - ); - } - - @Override - public String getConstructor() { - return "tableSwitch"; - } - } - - @EqualsAndHashCode - public static class c_lookupSwitch extends Statement { - - public Immediate immediate; - - public List stmts; - - - public c_lookupSwitch(Immediate immediate, List stmts) { - - this.immediate = immediate; - - this.stmts = stmts; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - IList iv_stmts = vf.list(); - - for(CaseStmt v: stmts) { - iv_stmts = iv_stmts.append(v.createVallangInstance(vf)); - } - - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - , iv_stmts - - ); - } - - @Override - public String getConstructor() { - return "lookupSwitch"; - } - } - - @EqualsAndHashCode - public static class c_identity extends Statement { - - public String local; - - public String identifier; - - public Type idType; - - - public c_identity(String local, String identifier, Type idType) { - - this.local = local; - - this.identifier = identifier; - - this.idType = idType; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_local = vf.string(local); - - IValue iv_identifier = vf.string(identifier); - - IValue iv_idType = idType.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_local - - , iv_identifier - - , iv_idType - - ); - } - - @Override - public String getConstructor() { - return "identity"; - } - } - - @EqualsAndHashCode - public static class c_identityNoType extends Statement { - - public String local; - - public String identifier; - - - public c_identityNoType(String local, String identifier) { - - this.local = local; - - this.identifier = identifier; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_local = vf.string(local); - - IValue iv_identifier = vf.string(identifier); - - - return vf.constructor(getVallangConstructor() - - , iv_local - - , iv_identifier - - ); - } - - @Override - public String getConstructor() { - return "identityNoType"; - } - } - - @EqualsAndHashCode - public static class c_assign extends Statement { - - public Variable var; - - public Expression expression; - - - public c_assign(Variable var, Expression expression) { - - this.var = var; - - this.expression = expression; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_var = var.createVallangInstance(vf); - - IValue iv_expression = expression.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_var - - , iv_expression - - ); - } - - @Override - public String getConstructor() { - return "assign"; - } - } - - @EqualsAndHashCode - public static class c_ifStmt extends Statement { - - public Expression exp; - - public String target; - - - public c_ifStmt(Expression exp, String target) { - - this.exp = exp; - - this.target = target; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_exp = exp.createVallangInstance(vf); - - IValue iv_target = vf.string(target); - - - return vf.constructor(getVallangConstructor() - - , iv_exp - - , iv_target - - ); - } - - @Override - public String getConstructor() { - return "ifStmt"; - } - } - - @EqualsAndHashCode - public static class c_retEmptyStmt extends Statement { - - - public c_retEmptyStmt() { - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - - return vf.constructor(getVallangConstructor() - - ); - } - - @Override - public String getConstructor() { - return "retEmptyStmt"; - } - } - - @EqualsAndHashCode - public static class c_retStmt extends Statement { - - public Immediate immediate; - - - public c_retStmt(Immediate immediate) { - - this.immediate = immediate; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - ); - } - - @Override - public String getConstructor() { - return "retStmt"; - } - } - - @EqualsAndHashCode - public static class c_returnEmptyStmt extends Statement { - - - public c_returnEmptyStmt() { - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - - return vf.constructor(getVallangConstructor() - - ); - } - - @Override - public String getConstructor() { - return "returnEmptyStmt"; - } - } - - @EqualsAndHashCode - public static class c_returnStmt extends Statement { - - public Immediate immediate; - - - public c_returnStmt(Immediate immediate) { - - this.immediate = immediate; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - ); - } - - @Override - public String getConstructor() { - return "returnStmt"; - } - } - - @EqualsAndHashCode - public static class c_throwStmt extends Statement { - - public Immediate immediate; - - - public c_throwStmt(Immediate immediate) { - - this.immediate = immediate; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_immediate = immediate.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_immediate - - ); - } - - @Override - public String getConstructor() { - return "throwStmt"; - } - } - - @EqualsAndHashCode - public static class c_invokeStmt extends Statement { - - public InvokeExp invokeExpression; - - - public c_invokeStmt(InvokeExp invokeExpression) { - - this.invokeExpression = invokeExpression; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_invokeExpression = invokeExpression.createVallangInstance(vf); - - - return vf.constructor(getVallangConstructor() - - , iv_invokeExpression - - ); - } - - @Override - public String getConstructor() { - return "invokeStmt"; - } - } - - @EqualsAndHashCode - public static class c_gotoStmt extends Statement { - - public String target; - - - public c_gotoStmt(String target) { - - this.target = target; - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - IValue iv_target = vf.string(target); - - - return vf.constructor(getVallangConstructor() - - , iv_target - - ); - } - - @Override - public String getConstructor() { - return "gotoStmt"; - } - } - - @EqualsAndHashCode - public static class c_nop extends Statement { - - - public c_nop() { - - } - - @Override - public IConstructor createVallangInstance(IValueFactory vf) { - - - - return vf.constructor(getVallangConstructor() - - ); - } - - @Override - public String getConstructor() { - return "nop"; - } - } - - + @Override + public String getBaseType() { + return "Statement"; + } + + protected String methodSignature; + protected int startLine; + protected int endLine; + + public static Statement label(String label) { + return new c_label(label); + } + + public static Statement breakpoint() { + return new c_breakpoint(); + } + + public static Statement enterMonitor(Immediate immediate) { + return new c_enterMonitor(immediate); + } + + public static Statement exitMonitor(Immediate immediate) { + return new c_exitMonitor(immediate); + } + + public static Statement tableSwitch(Immediate immediate, Integer min, Integer max, List stmts) { + return new c_tableSwitch(immediate, min, max, stmts); + } + + public static Statement lookupSwitch(Immediate immediate, List stmts) { + return new c_lookupSwitch(immediate, stmts); + } + + public static Statement identity(String local, String identifier, Type idType) { + return new c_identity(local, identifier, idType); + } + + public static Statement identityNoType(String local, String identifier) { + return new c_identityNoType(local, identifier); + } + + public static Statement assign(Variable var, Expression expression) { + return new c_assign(var, expression); + } + + public static Statement ifStmt(Expression exp, String target) { + return new c_ifStmt(exp, target); + } + + public static Statement retEmptyStmt() { + return new c_retEmptyStmt(); + } + + public static Statement retStmt(Immediate immediate) { + return new c_retStmt(immediate); + } + + public static Statement returnEmptyStmt() { + return new c_returnEmptyStmt(); + } + + public static Statement returnStmt(Immediate immediate) { + return new c_returnStmt(immediate); + } + + public static Statement throwStmt(Immediate immediate) { + return new c_throwStmt(immediate); + } + + public static Statement invokeStmt(InvokeExp invokeExpression) { + return new c_invokeStmt(invokeExpression); + } + + public static Statement gotoStmt(String target) { + return new c_gotoStmt(target); + } + + public static Statement nop() { + return new c_nop(); + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public int getStartLine() { + return startLine; + } + + public void setStartLine(int startLine) { + this.startLine = startLine; + } + + public int getEndLine() { + return endLine; + } + + public void setEndLine(int endLine) { + this.endLine = endLine; + } + + @EqualsAndHashCode + public static class c_label extends Statement { + + public String label; + + public c_label(String label) { + + this.label = label; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_label = vf.string(label); + + return vf.constructor(getVallangConstructor() + + , iv_label + + ); + } + + @Override + public String getConstructor() { + return "label"; + } + } + + @EqualsAndHashCode + public static class c_breakpoint extends Statement { + + public c_breakpoint() { + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + return vf.constructor(getVallangConstructor() + + ); + } + + @Override + public String getConstructor() { + return "breakpoint"; + } + } + + @EqualsAndHashCode + public static class c_enterMonitor extends Statement { + + public Immediate immediate; + + public c_enterMonitor(Immediate immediate) { + + this.immediate = immediate; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + ); + } + + @Override + public String getConstructor() { + return "enterMonitor"; + } + } + + @EqualsAndHashCode + public static class c_exitMonitor extends Statement { + + public Immediate immediate; + + public c_exitMonitor(Immediate immediate) { + + this.immediate = immediate; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + ); + } + + @Override + public String getConstructor() { + return "exitMonitor"; + } + } + + @EqualsAndHashCode + public static class c_tableSwitch extends Statement { + + public Immediate immediate; + + public Integer min; + + public Integer max; + + public List stmts; + + public c_tableSwitch(Immediate immediate, Integer min, Integer max, List stmts) { + + this.immediate = immediate; + + this.min = min; + + this.max = max; + + this.stmts = stmts; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + IValue iv_min = vf.integer(min); + + IValue iv_max = vf.integer(max); + + IList iv_stmts = vf.list(); + + for (CaseStmt v : stmts) { + iv_stmts = iv_stmts.append(v.createVallangInstance(vf)); + } + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + , iv_min + + , iv_max + + , iv_stmts + + ); + } + + @Override + public String getConstructor() { + return "tableSwitch"; + } + } + + @EqualsAndHashCode + public static class c_lookupSwitch extends Statement { + + public Immediate immediate; + + public List stmts; + + public c_lookupSwitch(Immediate immediate, List stmts) { + + this.immediate = immediate; + + this.stmts = stmts; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + IList iv_stmts = vf.list(); + + for (CaseStmt v : stmts) { + iv_stmts = iv_stmts.append(v.createVallangInstance(vf)); + } + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + , iv_stmts + + ); + } + + @Override + public String getConstructor() { + return "lookupSwitch"; + } + } + + @EqualsAndHashCode + public static class c_identity extends Statement { + + public String local; + + public String identifier; + + public Type idType; + + public c_identity(String local, String identifier, Type idType) { + + this.local = local; + + this.identifier = identifier; + + this.idType = idType; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_local = vf.string(local); + + IValue iv_identifier = vf.string(identifier); + + IValue iv_idType = idType.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_local + + , iv_identifier + + , iv_idType + + ); + } + + @Override + public String getConstructor() { + return "identity"; + } + } + + @EqualsAndHashCode + public static class c_identityNoType extends Statement { + + public String local; + + public String identifier; + + public c_identityNoType(String local, String identifier) { + + this.local = local; + + this.identifier = identifier; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_local = vf.string(local); + + IValue iv_identifier = vf.string(identifier); + + return vf.constructor(getVallangConstructor() + + , iv_local + + , iv_identifier + + ); + } + + @Override + public String getConstructor() { + return "identityNoType"; + } + } + + @EqualsAndHashCode + public static class c_assign extends Statement { + + public Variable var; + + public Expression expression; + + public c_assign(Variable var, Expression expression) { + + this.var = var; + + this.expression = expression; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_var = var.createVallangInstance(vf); + + IValue iv_expression = expression.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_var + + , iv_expression + + ); + } + + @Override + public String getConstructor() { + return "assign"; + } + } + + @EqualsAndHashCode + public static class c_ifStmt extends Statement { + + public Expression exp; + + public String target; + + public c_ifStmt(Expression exp, String target) { + + this.exp = exp; + + this.target = target; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_exp = exp.createVallangInstance(vf); + + IValue iv_target = vf.string(target); + + return vf.constructor(getVallangConstructor() + + , iv_exp + + , iv_target + + ); + } + + @Override + public String getConstructor() { + return "ifStmt"; + } + } + + @EqualsAndHashCode + public static class c_retEmptyStmt extends Statement { + + public c_retEmptyStmt() { + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + return vf.constructor(getVallangConstructor() + + ); + } + + @Override + public String getConstructor() { + return "retEmptyStmt"; + } + } + + @EqualsAndHashCode + public static class c_retStmt extends Statement { + + public Immediate immediate; + + public c_retStmt(Immediate immediate) { + + this.immediate = immediate; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + ); + } + + @Override + public String getConstructor() { + return "retStmt"; + } + } + + @EqualsAndHashCode + public static class c_returnEmptyStmt extends Statement { + + public c_returnEmptyStmt() { + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + return vf.constructor(getVallangConstructor() + + ); + } + + @Override + public String getConstructor() { + return "returnEmptyStmt"; + } + } + + @EqualsAndHashCode + public static class c_returnStmt extends Statement { + + public Immediate immediate; + + public c_returnStmt(Immediate immediate) { + + this.immediate = immediate; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + ); + } + + @Override + public String getConstructor() { + return "returnStmt"; + } + } + + @EqualsAndHashCode + public static class c_throwStmt extends Statement { + + public Immediate immediate; + + public c_throwStmt(Immediate immediate) { + + this.immediate = immediate; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_immediate = immediate.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_immediate + + ); + } + + @Override + public String getConstructor() { + return "throwStmt"; + } + } + + @EqualsAndHashCode + public static class c_invokeStmt extends Statement { + + public InvokeExp invokeExpression; + + public c_invokeStmt(InvokeExp invokeExpression) { + + this.invokeExpression = invokeExpression; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_invokeExpression = invokeExpression.createVallangInstance(vf); + + return vf.constructor(getVallangConstructor() + + , iv_invokeExpression + + ); + } + + @Override + public String getConstructor() { + return "invokeStmt"; + } + } + + @EqualsAndHashCode + public static class c_gotoStmt extends Statement { + + public String target; + + public c_gotoStmt(String target) { + + this.target = target; + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + IValue iv_target = vf.string(target); + + return vf.constructor(getVallangConstructor() + + , iv_target + + ); + } + + @Override + public String getConstructor() { + return "gotoStmt"; + } + } + + @EqualsAndHashCode + public static class c_nop extends Statement { + + public c_nop() { + + } + + @Override + public IConstructor createVallangInstance(IValueFactory vf) { + + return vf.constructor(getVallangConstructor() + + ); + } + + @Override + public String getConstructor() { + return "nop"; + } + } + } \ No newline at end of file diff --git a/src/main/rascal/lang/jimple/core/Syntax.rsc b/src/main/rascal/lang/jimple/core/Syntax.rsc index ec65eb64..b2979589 100644 --- a/src/main/rascal/lang/jimple/core/Syntax.rsc +++ b/src/main/rascal/lang/jimple/core/Syntax.rsc @@ -74,7 +74,7 @@ data Variable | staticFieldRef(FieldSignature field) ; -data Statement +data Statement(String methodSignature = "", int startLine = -1, int endLine = -1) = label(Label label) | breakpoint() | enterMonitor(Immediate immediate) diff --git a/src/test/java/samples/operators/IntOps.java b/src/test/java/samples/operators/IntOps.java index 36f67cd3..cd37b9d0 100644 --- a/src/test/java/samples/operators/IntOps.java +++ b/src/test/java/samples/operators/IntOps.java @@ -16,126 +16,126 @@ public static void main(String[] args) throws InvocationTargetException, Illegal } */ - public void addition() { - int a = 5; - int b = 5; - int d = a + b; - System.out.println(d); - } - - public void subtraction() { - int a = 5; - int b = 5; - int d = b - a; - System.out.println(d); - } - - public void multiplication() { - int a = 5; - int b = 5; - int d = b * a; - System.out.println(d); - } - - public void division() { - int a = 5; - int b = 5; - int d = b / a; - System.out.println(d); - } - - public void modulus() { - int a = 5; - int b = 5; - int d = b % a; - System.out.println(d); - } - - public void simpleAssignmentOperator() { - int a = 5; - int d = a; - System.out.println(d); - } - - public void bitwiseAnd() { - int a = 5; - int b = 5; - int d = a & b; - System.out.println(d); - } - - public void bitwiseOr() { - int a = 5; - int b = 5; - int d = a | b; - System.out.println(d); - } - - public void bitwiseXor() { - int a = 5; - int b = 5; - int d = a ^ b; - System.out.println(d); - } - - public void bitwiseCompliment() { - int a = 5; - int d = ~a; - System.out.println(d); - } - - public void bitwiseLeftShift() { - int a = 5; - int d = a << 2; - System.out.println(d); - } - - public void bitwiseRightShift() { - int a = 5; - int d = a >> 2; - System.out.println(d); - } - - public void bitwiseRightShiftZerofill() { - int a = 5; - int d = a >>> 2; - System.out.println(d); - } - - public void equals() { - int a = 5; - int b = 5; - boolean result = (a == b); - System.out.println(result); - } - - public void notEquals() { - int a = 5; - int b = 5; - boolean result = (a != b); - System.out.println(result); - } - - public void greateThan() { - int a = 5; - int b = 5; - boolean result = (a > b); - System.out.println(result); - } - - public void lessThan() { - int a = 5; - int b = 5; - boolean result = (a < b); - System.out.println(result); - } - - public void greaterOrEqualsThan() { - int a = 5; - int b = 5; - boolean result = (a >= b); - System.out.println(result); - } +// public void addition() { +// int a = 5; +// int b = 5; +// int d = a + b; +// System.out.println(d); +// } +// +// public void subtraction() { +// int a = 5; +// int b = 5; +// int d = b - a; +// System.out.println(d); +// } +// +// public void multiplication() { +// int a = 5; +// int b = 5; +// int d = b * a; +// System.out.println(d); +// } +// +// public void division() { +// int a = 5; +// int b = 5; +// int d = b / a; +// System.out.println(d); +// } +// +// public void modulus() { +// int a = 5; +// int b = 5; +// int d = b % a; +// System.out.println(d); +// } +// +// public void simpleAssignmentOperator() { +// int a = 5; +// int d = a; +// System.out.println(d); +// } +// +// public void bitwiseAnd() { +// int a = 5; +// int b = 5; +// int d = a & b; +// System.out.println(d); +// } +// +// public void bitwiseOr() { +// int a = 5; +// int b = 5; +// int d = a | b; +// System.out.println(d); +// } +// +// public void bitwiseXor() { +// int a = 5; +// int b = 5; +// int d = a ^ b; +// System.out.println(d); +// } +// +// public void bitwiseCompliment() { +// int a = 5; +// int d = ~a; +// System.out.println(d); +// } +// +// public void bitwiseLeftShift() { +// int a = 5; +// int d = a << 2; +// System.out.println(d); +// } +// +// public void bitwiseRightShift() { +// int a = 5; +// int d = a >> 2; +// System.out.println(d); +// } +// +// public void bitwiseRightShiftZerofill() { +// int a = 5; +// int d = a >>> 2; +// System.out.println(d); +// } +// +// public void equals() { +// int a = 5; +// int b = 5; +// boolean result = (a == b); +// System.out.println(result); +// } +// +// public void notEquals() { +// int a = 5; +// int b = 5; +// boolean result = (a != b); +// System.out.println(result); +// } +// +// public void greateThan() { +// int a = 5; +// int b = 5; +// boolean result = (a > b); +// System.out.println(result); +// } +// +// public void lessThan() { +// int a = 5; +// int b = 5; +// boolean result = (a < b); +// System.out.println(result); +// } +// +// public void greaterOrEqualsThan() { +// int a = 5; +// int b = 5; +// boolean result = (a >= b); +// System.out.println(result); +// } public void lessOrEqualsThan() { int a = 5; @@ -143,4 +143,11 @@ public void lessOrEqualsThan() { boolean result = (a <= b); System.out.println(result); } + + public void ternaryExpression() { + int a = 5; + int b = 5; + int result = (a == b) ? 1 : 0; + System.out.println(result); + } } From 258d0dc1d988a513b7ae46c8c716c7e440bc1ed4 Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Sun, 7 Feb 2021 20:07:02 -0300 Subject: [PATCH 02/16] fix the execution with multiple branches / frames --- .../internal/BranchInstructionFlow.java | 107 +-- .../java/lang/jimple/internal/Decompiler.java | 752 ++++++++++-------- .../lang/jimple/internal/Environment.java | 17 + .../lang/jimple/internal/InstructionFlow.java | 16 +- .../internal/SingleInstructionFlow.java | 47 +- src/test/.DS_Store | Bin 0 -> 6148 bytes .../lang/jimple/internal/TestDecompiler.java | 18 + .../java/samples/SimpleLambdaExpression.java | 13 + src/test/java/samples/operators/IntOps.java | 14 +- src/test/rascal/TestSuite.rsc | 28 + src/test/resources/.DS_Store | Bin 0 -> 6148 bytes .../resources/sootOutput/org.slf4j.MDC.jimple | 279 +++++++ .../resources/sootOutput/org/slf4j/MDC.class | Bin 0 -> 2509 bytes 13 files changed, 884 insertions(+), 407 deletions(-) create mode 100644 src/main/java/lang/jimple/internal/Environment.java create mode 100644 src/test/.DS_Store create mode 100644 src/test/java/samples/SimpleLambdaExpression.java create mode 100644 src/test/rascal/TestSuite.rsc create mode 100644 src/test/resources/.DS_Store create mode 100644 src/test/resources/sootOutput/org.slf4j.MDC.jimple create mode 100644 src/test/resources/sootOutput/org/slf4j/MDC.class diff --git a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java index 0139f8eb..f7822168 100644 --- a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java +++ b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java @@ -9,75 +9,88 @@ public class BranchInstructionFlow implements InstructionFlow { - private Expression condition; - private String target; - private InstructionFlow left; - private InstructionFlow right; - private BranchState status; + private Environment left; + private Environment right; + + private Expression condition; + + private String targetStatement; + private String mergeStatement; + + private BranchState status; enum BranchState { LEFT, RIGHT, - ReadyToMerge; + ReadyToMerge } public BranchInstructionFlow(Expression condition, String target) { this.condition = condition; - this.target = target; - left = new SingleInstructionFlow(); - right = new SingleInstructionFlow(); + this.targetStatement = target; + left = new Environment(); + right = new Environment(); status = BranchState.LEFT; } - - public void push(Operand operand) { - switch(status) { - case LEFT: left.push(operand); break; - case RIGHT: right.push(operand); break; - case ReadyToMerge: left.push(operand); right.push(operand); - } + + + @Override + public Collection merge() { + List res = new ArrayList<>(); + + res.add(Statement.ifStmt(condition, targetStatement)); + res.addAll(left.instructions); + res.addAll(right.instructions); + + return res; } - - public Operand pop() { - switch(status) { - case LEFT: return left.pop(); - case RIGHT: return right.pop(); - case ReadyToMerge: return null; + + @Override + public boolean matchMergePoint(String label) { + if(status.equals(BranchState.LEFT)) { + return this.targetStatement.equals(label); } - return null; + else if(status.equals(BranchState.RIGHT)) { + return this.mergeStatement.equals(label); + } + return false; } - - public void addInstruction(Statement stmt) { + + @Override + public List environments() { + List res = new ArrayList<>(); switch(status) { - case LEFT: left.addInstruction(stmt); break; - case RIGHT: right.addInstruction(stmt); break; - case ReadyToMerge: left.addInstruction(stmt); right.addInstruction(stmt); + case LEFT: res.add(left); break; + case RIGHT: res.add(right); break; + case ReadyToMerge: res.add(left); res.add(right); } + return res; } - - public void clearOperandStack() { - left.clearOperandStack(); - right.clearOperandStack(); + + @Override + public void notifyGotoStmt(String label) { + if(status.equals(BranchState.LEFT)) { + mergeStatement = label; + } } @Override - public int sizeOfOperandStack() { + public void nextBranch() { switch(status) { - case LEFT: return left.sizeOfOperandStack(); - case RIGHT: return right.sizeOfOperandStack(); - case ReadyToMerge: return left.sizeOfOperandStack() + right.sizeOfOperandStack(); + case LEFT: status = BranchState.RIGHT; break; + case RIGHT: status = BranchState.ReadyToMerge; break; + case ReadyToMerge: // } - return 0; } - + @Override - public Collection merge() { - List res = new ArrayList<>(); - - res.add(Statement.ifStmt(condition, target)); - res.addAll(left.merge()); - res.addAll(right.merge()); - - return res; + public boolean isBranch() { + return true; } -} + @Override + public boolean readyToMerge(String label) { + this.targetStatement = label; + return status.equals(BranchState.ReadyToMerge); + } +} \ No newline at end of file diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index ad5cd7d6..3994983c 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -312,32 +312,48 @@ public List instructions() { return new ArrayList<>(stack.peek().merge()); } - private void addInstruction(Statement s) { - stack.peek().addInstruction(s); + private void notifyGotoStmt(String label) { + stack.peek().notifyGotoStmt(label); } - private void pushOperand(Operand o) { - stack.peek().push(o); + private void notifyReturn() { + for(Environment env: stack.peek().environments()) { + env.operands.clear(); + } } - - private Operand pop() { - return stack.peek().pop(); + + private void nextBranch() { + stack.peek().nextBranch(); } - private int sizeOfOperandStack() { - return stack.peek().sizeOfOperandStack(); + private boolean isBranch() { + return stack.peek().isBranch(); } - private void notifyReturn() { - stack.peek().clearOperandStack(); + + private boolean readyToMerge(String label) { + return stack.peek().readyToMerge(label); } @Override public void visitLabel(Label label) { - addInstruction(Statement.label(label.toString())); if (catchClauses.containsKey(label.toString())) { - CatchClause c = catchClauses.get(label.toString()); - pushOperand(new Operand(c.exception, Immediate.caughtException())); - referencedLabels.add(label.toString()); + for(Environment env: stack.peek().environments()) { + CatchClause c = catchClauses.get(label.toString()); + env.operands.push(new Operand(c.exception, Immediate.caughtException())); + referencedLabels.add(label.toString()); + } + } + + if(isBranch() && stack.peek().matchMergePoint(label.toString())) { + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.label(label.toString())); + } + nextBranch(); + } + else if(readyToMerge(label.toString()) && stack.size() > 1) { + List stmts = new ArrayList<>(stack.pop().merge()); + + stack.peek().environments().get(0).instructions.addAll(stmts); } } @@ -391,7 +407,9 @@ public void visitIincInsn(int idx, int increment) { Immediate rhs = newIntValueImmediate(increment); Expression expression = newPlusExpression(lhs, rhs); - addInstruction(assignmentStmt(Variable.localVariable(var), expression)); + for(Environment env: stack.peek().environments()) { + env.instructions.add(assignmentStmt(Variable.localVariable(var), expression)); + } super.visitIincInsn(idx, increment); } @@ -867,130 +885,141 @@ public void visitInvokeDynamicInsn(String name, String descriptor, Handle bsmh, List args = new ArrayList<>(); - for (int i = 0; i < argTypes.size(); i++) { - args.add(0, pop().immediate); - } - - InvokeExp exp = InvokeExp.dynamicInvoke(bootstrapMethod, bootstrapArgs, method, args); + for(Environment env: stack.peek().environments()) { + for (int i = 0; i < argTypes.size(); i++) { + args.add(0, env.operands.pop().immediate); + } + InvokeExp exp = InvokeExp.dynamicInvoke(bootstrapMethod, bootstrapArgs, method, args); - addInstruction(Statement.invokeStmt(exp)); + env.instructions.add(Statement.invokeStmt(exp)); + } super.visitInvokeDynamicInsn(name, descriptor, bsmh, bootstrapMethodArguments); } @Override public void visitLdcInsn(Object value) { - pushOperand(new Operand(toJimpleTypedValue(value))); + for(Environment env: stack.peek().environments()) { + env.operands.push(new Operand(toJimpleTypedValue(value))); + } super.visitLdcInsn(value); } @Override public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - Immediate key = pop().immediate; + for(Environment env: stack.peek().environments()) { + Immediate key = env.operands.pop().immediate; - List caseStmts = new ArrayList<>(); + List caseStmts = new ArrayList<>(); - for (int i = 0; i < keys.length; i++) { - caseStmts.add(CaseStmt.caseOption(keys[i], labels[i].toString())); - } + for (int i = 0; i < keys.length; i++) { + caseStmts.add(CaseStmt.caseOption(keys[i], labels[i].toString())); + } - if (dflt != null) { - caseStmts.add(CaseStmt.defaultOption(dflt.toString())); + if (dflt != null) { + caseStmts.add(CaseStmt.defaultOption(dflt.toString())); + } + env.instructions.add(Statement.lookupSwitch(key, caseStmts)); } - - addInstruction(Statement.lookupSwitch(key, caseStmts)); super.visitLookupSwitchInsn(dflt, keys, labels); } @Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { - Immediate key = pop().immediate; - List caseStmts = new ArrayList<>(); + for(Environment env: stack.peek().environments()) { + Immediate key = env.operands.pop().immediate; + List caseStmts = new ArrayList<>(); - for (Label label : labels) { - caseStmts.add(CaseStmt.caseOption(label.getOffset(), label.toString())); - } + for (Label label : labels) { + caseStmts.add(CaseStmt.caseOption(label.getOffset(), label.toString())); + } - if (dflt != null) { - caseStmts.add(CaseStmt.defaultOption(dflt.toString())); + if (dflt != null) { + caseStmts.add(CaseStmt.defaultOption(dflt.toString())); + } + env.instructions.add(Statement.tableSwitch(key, min, max, caseStmts)); } - addInstruction(Statement.tableSwitch(key, min, max, caseStmts)); super.visitTableSwitchInsn(min, max, dflt, labels); } @Override public void visitJumpInsn(int opcode, Label label) { if (opcode == Opcodes.GOTO) { - addInstruction(Statement.gotoStmt(label.toString())); + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.gotoStmt(label.toString())); + } + notifyGotoStmt(label.toString()); // TODO: investigate this decision here. } else if (opcode == Opcodes.JSR) { throw RuntimeExceptionFactory.illegalArgument(vf.string("unsupported instruction JSR" + opcode), null, null); } else { - Expression exp = null; - Immediate first = pop().immediate; - Immediate second = Immediate.iValue(Value.intValue(0)); - switch (opcode) { - case Opcodes.IFEQ: - exp = Expression.cmpeq(first, second); - break; - case Opcodes.IFNE: - exp = Expression.cmpne(first, second); - break; - case Opcodes.IFLT: - exp = Expression.cmplt(first, second); - break; - case Opcodes.IFLE: - exp = Expression.cmple(first, second); - break; - case Opcodes.IFGT: - exp = Expression.cmpgt(first, second); - break; - case Opcodes.IFGE: - exp = Expression.cmpge(first, second); - break; - case Opcodes.IF_ICMPEQ: - second = pop().immediate; - exp = Expression.cmpeq(second, first); - break; - case Opcodes.IF_ICMPNE: - second = pop().immediate; - exp = Expression.cmpne(second, first); - break; - case Opcodes.IF_ICMPLT: - second = pop().immediate; - exp = Expression.cmplt(second, first); - break; - case Opcodes.IF_ICMPGE: - second = pop().immediate; - exp = Expression.cmpge(second, first); - break; - case Opcodes.IF_ICMPGT: - second = pop().immediate; - exp = Expression.cmpgt(second, first); - break; - case Opcodes.IF_ICMPLE: - second = pop().immediate; - exp = Expression.cmple(second, first); - break; - case Opcodes.IF_ACMPEQ: - second = pop().immediate; - exp = Expression.cmpeq(second, first); - break; - case Opcodes.IF_ACMPNE: - second = pop().immediate; - exp = Expression.cmpne(second, first); - break; - case Opcodes.IFNULL: - exp = Expression.isNull(first); - break; - case Opcodes.IFNONNULL: - exp = Expression.isNotNull(first); - break; - default: - throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, - null); + for(Environment env: stack.peek().environments()) { + Expression exp = null; + Immediate first = env.operands.pop().immediate; + Immediate second = Immediate.iValue(Value.intValue(0)); + switch (opcode) { + case Opcodes.IFEQ: + exp = Expression.cmpeq(first, second); + break; + case Opcodes.IFNE: + exp = Expression.cmpne(first, second); + break; + case Opcodes.IFLT: + exp = Expression.cmplt(first, second); + break; + case Opcodes.IFLE: + exp = Expression.cmple(first, second); + break; + case Opcodes.IFGT: + exp = Expression.cmpgt(first, second); + break; + case Opcodes.IFGE: + exp = Expression.cmpge(first, second); + break; + case Opcodes.IF_ICMPEQ: + second = env.operands.pop().immediate; + exp = Expression.cmpeq(second, first); + break; + case Opcodes.IF_ICMPNE: + second = env.operands.pop().immediate; + exp = Expression.cmpne(second, first); + break; + case Opcodes.IF_ICMPLT: + second = env.operands.pop().immediate; + exp = Expression.cmplt(second, first); + break; + case Opcodes.IF_ICMPGE: + second = env.operands.pop().immediate; + exp = Expression.cmpge(second, first); + break; + case Opcodes.IF_ICMPGT: + second = env.operands.pop().immediate; + exp = Expression.cmpgt(second, first); + break; + case Opcodes.IF_ICMPLE: + second = env.operands.pop().immediate; + exp = Expression.cmple(second, first); + break; + case Opcodes.IF_ACMPEQ: + second = env.operands.pop().immediate; + exp = Expression.cmpeq(second, first); + break; + case Opcodes.IF_ACMPNE: + second = env.operands.pop().immediate; + exp = Expression.cmpne(second, first); + break; + case Opcodes.IFNULL: + exp = Expression.isNull(first); + break; + case Opcodes.IFNONNULL: + exp = Expression.isNotNull(first); + break; + default: + throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, + null); + } + stack.push(new BranchInstructionFlow(exp, label.toString())); } - addInstruction(Statement.ifStmt(exp, label.toString())); } referencedLabels.add(label.toString()); super.visitJumpInsn(opcode, label); @@ -1003,27 +1032,30 @@ public void visitJumpInsn(int opcode, Label label) { private void invokeMethodIns(String owner, String name, String descriptor, boolean isStatic, InvokeExpressionFactory factory) { MethodSignature signature = methodSignature(owner.replace("/", "."), name, descriptor); - List args = new ArrayList<>(); - for (int i = 0; i < signature.formals.size(); i++) { - args.add(0, pop().immediate); - } + for(Environment env: stack.peek().environments()) { + List args = new ArrayList<>(); - InvokeExp exp = null; + for (int i = 0; i < signature.formals.size(); i++) { + args.add(0, env.operands.pop().immediate); + } - if (!isStatic) { - String reference = ((Immediate.c_local) pop().immediate).localName; - exp = factory.createInvokeExpression(reference, signature, args); - } else { - exp = factory.createInvokeExpression(null, signature, args); - } + InvokeExp exp = null; - if (signature.returnType.equals(Type.TVoid())) { - addInstruction(Statement.invokeStmt(exp)); - } else { - LocalVariableDeclaration local = createLocal(signature.returnType); - addInstruction(assignmentStmt(Variable.localVariable(local.local), Expression.invokeExp(exp))); - pushOperand(new Operand(local)); + if (!isStatic) { + String reference = ((Immediate.c_local) env.operands.pop().immediate).localName; + exp = factory.createInvokeExpression(reference, signature, args); + } else { + exp = factory.createInvokeExpression(null, signature, args); + } + + if (signature.returnType.equals(Type.TVoid())) { + env.instructions.add(Statement.invokeStmt(exp)); + } else { + LocalVariableDeclaration local = createLocal(signature.returnType); + env.instructions.add(assignmentStmt(Variable.localVariable(local.local), Expression.invokeExp(exp))); + env.operands.push(new Operand(local)); + } } } @@ -1052,7 +1084,9 @@ private LocalVariableDeclaration findLocalVariable(int idx) { */ private void loadIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); - pushOperand(new Operand(local)); + for(Environment env: stack.peek().environments()) { + env.operands.push(new Operand(local)); + } } /* @@ -1060,8 +1094,10 @@ private void loadIns(int var) { */ private void storeIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); - Immediate immediate = pop().immediate; - addInstruction(assignmentStmt(Variable.localVariable(local.local), Expression.immediate(immediate))); + for (Environment env : stack.peek().environments()) { + Immediate immediate = env.operands.pop().immediate; + env.instructions.add(assignmentStmt(Variable.localVariable(local.local), Expression.immediate(immediate))); + } } /* @@ -1071,142 +1107,176 @@ private void storeIns(int var) { */ private void retIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); - addInstruction(Statement.retStmt(Immediate.local(local.local))); + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.retStmt(Immediate.local(local.local))); + } } private void newInstanceIns(Type type) { LocalVariableDeclaration newLocal = createLocal(type); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newInstance(type))); - pushOperand(new Operand(newLocal)); + for(Environment env: stack.peek().environments()) { + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newInstance(type))); + env.operands.push(new Operand(newLocal)); + } } private void aNewArrayIns(Type type) { - Operand operand = pop(); - LocalVariableDeclaration newLocal = createLocal(Type.TArray(type)); - c_iValue value = (Immediate.c_iValue) operand.immediate; + for(Environment env: stack.peek().environments()) { + Operand operand = env.operands.pop(); + LocalVariableDeclaration newLocal = createLocal(Type.TArray(type)); + c_iValue value = (Immediate.c_iValue) operand.immediate; - assert (value.v instanceof Value.c_intValue); + assert (value.v instanceof Value.c_intValue); - Integer size = ((Value.c_intValue) value.v).iv; + Integer size = ((Value.c_intValue) value.v).iv; - List dims = new ArrayList<>(); - dims.add(ArrayDescriptor.fixedSize(size)); + List dims = new ArrayList<>(); + dims.add(ArrayDescriptor.fixedSize(size)); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newArray(type, dims))); - pushOperand(new Operand(newLocal)); + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), Expression.newArray(type, dims))); + env.operands.push(new Operand(newLocal)); + } } /* * Add a nop instruction */ private void nopIns() { - addInstruction(Statement.nop()); + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.nop()); + } } /* * Load a null value into the top of the operand stack. */ private void acconstNullIns() { - pushOperand(new Operand(Type.TNull(), Immediate.iValue(Value.nullValue()))); + for(Environment env: stack.peek().environments()) { + env.operands.push(new Operand(Type.TNull(), Immediate.iValue(Value.nullValue()))); + } } /* * Load an int const into the top of the operand stack. */ private void loadIntConstIns(int value, String descriptor) { - pushOperand(new Operand(type(descriptor), Immediate.iValue(Value.intValue(value)))); + for(Environment env: stack.peek().environments()) { + env.operands.push(new Operand(type(descriptor), Immediate.iValue(Value.intValue(value)))); + } } /* * Load a float const into the top of the operand stack. */ private void loadRealConstIns(float value, String descriptor) { - pushOperand(new Operand(type(descriptor), Immediate.iValue(Value.floatValue(value)))); + for (Environment env : stack.peek().environments()) { + env.operands.push(new Operand(type(descriptor), Immediate.iValue(Value.floatValue(value)))); + } } /* * Neg instruction (INEG, LNEG, FNEG, DNEG) */ private void negIns(Type type) { - Operand operand = pop(); + for(Environment env: stack.peek().environments()) { + Operand operand = env.operands.pop(); - LocalVariableDeclaration newLocal = createLocal(type); + LocalVariableDeclaration newLocal = createLocal(type); - Expression expression = Expression.neg(operand.immediate); + Expression expression = Expression.neg(operand.immediate); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), expression)); + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), expression)); - pushOperand(new Operand(newLocal)); + env.operands.push(new Operand(newLocal)); + } } /* * Instructions supporting binarya operations. */ private void binOperatorIns(Type type, BinExpressionFactory factory) { - Operand rhs = pop(); - Operand lhs = pop(); + for(Environment env: stack.peek().environments()) { + Operand rhs = env.operands.pop(); + Operand lhs = env.operands.pop(); - LocalVariableDeclaration newLocal = createLocal(type); + LocalVariableDeclaration newLocal = createLocal(type); - Expression expression = factory.createExpression(lhs.immediate, rhs.immediate); + Expression expression = factory.createExpression(lhs.immediate, rhs.immediate); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), expression)); + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), expression)); - pushOperand(new Operand(newLocal)); + env.operands.push(new Operand(newLocal)); + } } private void simpleCastIns(Type targetType) { - Operand operand = pop(); - LocalVariableDeclaration newLocal = createLocal(targetType); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), - Expression.cast(targetType, operand.immediate))); - pushOperand(new Operand(newLocal)); + for(Environment env: stack.peek().environments()) { + Operand operand = env.operands.pop(); + LocalVariableDeclaration newLocal = createLocal(targetType); + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), + Expression.cast(targetType, operand.immediate))); + env.operands.push(new Operand(newLocal)); + } } private void instanceOfIns(Type type) { - Operand operand = pop(); - LocalVariableDeclaration newLocal = createLocal(Type.TBoolean()); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), - Expression.instanceOf(type, operand.immediate))); - pushOperand(new Operand(newLocal)); + for(Environment env: stack.peek().environments()) { + Operand operand = env.operands.pop(); + LocalVariableDeclaration newLocal = createLocal(Type.TBoolean()); + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), + Expression.instanceOf(type, operand.immediate))); + env.operands.push(new Operand(newLocal)); + } } private void returnIns() { - Operand operand = pop(); - addInstruction(Statement.returnStmt(operand.immediate)); - // TODO: perhaps we should call an exit monitor here. - notifyReturn(); + for(Environment env: stack.peek().environments()) { + Operand operand = env.operands.pop(); + env.instructions.add(Statement.returnStmt(operand.immediate)); + // TODO: perhaps we should call an exit monitor here. + notifyReturn(); + } } private void returnVoidIns() { - addInstruction(Statement.returnEmptyStmt()); - // TODO: perhaps we should call an exit monitor here. - notifyReturn(); + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.returnEmptyStmt()); + // TODO: perhaps we should call an exit monitor here. + notifyReturn(); + } } private void arrayLengthIns() { - Operand arrayRef = pop(); - LocalVariableDeclaration newLocal = createLocal("I"); - addInstruction( - assignmentStmt(Variable.localVariable(newLocal.local), Expression.lengthOf(arrayRef.immediate))); - pushOperand(new Operand(newLocal)); + for(Environment env: stack.peek().environments()) { + Operand arrayRef = env.operands.pop(); + LocalVariableDeclaration newLocal = createLocal("I"); + env.instructions.add( + assignmentStmt(Variable.localVariable(newLocal.local), Expression.lengthOf(arrayRef.immediate))); + env.operands.push(new Operand(newLocal)); + } } private void throwIns() { - Operand reference = pop(); - addInstruction(Statement.throwStmt(reference.immediate)); - notifyReturn(); - pushOperand(reference); + for(Environment env: stack.peek().environments()) { + Operand reference = env.operands.pop(); + env.instructions.add(Statement.throwStmt(reference.immediate)); + notifyReturn(); + env.operands.push(reference); + } } private void monitorEnterIns() { - Operand reference = pop(); - addInstruction(Statement.enterMonitor(reference.immediate)); + for(Environment env: stack.peek().environments()) { + Operand reference = env.operands.pop(); + env.instructions.add(Statement.enterMonitor(reference.immediate)); + } } private void monitorExitIns() { - Operand reference = pop(); - addInstruction(Statement.exitMonitor(reference.immediate)); + for(Environment env: stack.peek().environments()) { + Operand reference = env.operands.pop(); + env.instructions.add(Statement.exitMonitor(reference.immediate)); + } } /* @@ -1215,21 +1285,23 @@ private void monitorExitIns() { * the stack. */ private void arraySubscriptIns() { - Operand idx = pop(); - Operand ref = pop(); + for(Environment env: stack.peek().environments()) { + Operand idx = env.operands.pop(); + Operand ref = env.operands.pop(); - Type baseType = ref.type; + Type baseType = ref.type; - if (baseType instanceof Type.c_TArray) { - baseType = ((Type.c_TArray) baseType).baseType; - } + if (baseType instanceof Type.c_TArray) { + baseType = ((Type.c_TArray) baseType).baseType; + } - LocalVariableDeclaration newLocal = createLocal(baseType); + LocalVariableDeclaration newLocal = createLocal(baseType); - addInstruction(assignmentStmt(Variable.localVariable(newLocal.local), - newArraySubscript(((Immediate.c_local) ref.immediate).localName, idx.immediate))); + env.instructions.add(assignmentStmt(Variable.localVariable(newLocal.local), + newArraySubscript(((Immediate.c_local) ref.immediate).localName, idx.immediate))); - pushOperand(new Operand(newLocal)); + env.operands.push(new Operand(newLocal)); + } } /* @@ -1241,20 +1313,24 @@ private void arraySubscriptIns() { * After popping value, idx, and array, no value is introduced into the stack. */ private void storeIntoArrayIns() { - Immediate value = pop().immediate; - Immediate idx = pop().immediate; - Immediate arrayRef = pop().immediate; + for(Environment env: stack.peek().environments()) { + Immediate value = env.operands.pop().immediate; + Immediate idx = env.operands.pop().immediate; + Immediate arrayRef = env.operands.pop().immediate; - Variable var = Variable.arrayRef(((Immediate.c_local) arrayRef).localName, idx); + Variable var = Variable.arrayRef(((Immediate.c_local) arrayRef).localName, idx); - addInstruction(assignmentStmt(var, Expression.immediate(value))); + env.instructions.add(assignmentStmt(var, Expression.immediate(value))); + } } /* * Removes an operand from the stack. */ private void popIns() { - pop(); + for(Environment env: stack.peek().environments()) { + env.operands.pop(); + } } /* @@ -1262,10 +1338,12 @@ private void popIns() { * the first operand is either a long or a double, it removes just one operand. */ private void pop2Ins() { - Operand value = pop(); + for(Environment env: stack.peek().environments()) { + Operand value = env.operands.pop(); - if (allCategory1(value.type)) { - pop(); + if (allCategory1(value.type)) { + env.operands.pop(); + } } } @@ -1273,24 +1351,28 @@ private void pop2Ins() { * Duplicate the top operand stack value */ private void dupIns() { - Operand value = pop(); + for(Environment env: stack.peek().environments()) { + Operand value = env.operands.pop(); - pushOperand(value); - pushOperand(value); + env.operands.push(value); + env.operands.push(value); + } } /* * Duplicate the top operand stack value and insert the copy two values down. */ private void dupX1Ins() { - assert sizeOfOperandStack() >= 2; + for(Environment env: stack.peek().environments()) { + assert env.operands.size() >= 2; - Operand value1 = pop(); - Operand value2 = pop(); + Operand value1 = env.operands.pop(); + Operand value2 = env.operands.pop(); - pushOperand(value1); - pushOperand(value2); - pushOperand(value1); + env.operands.push(value1); + env.operands.push(value2); + env.operands.push(value1); + } } /* @@ -1298,22 +1380,24 @@ private void dupX1Ins() { * down. */ private void dupX2Ins() { - assert sizeOfOperandStack() >= 2; - - Operand value1 = pop(); - - if (allCategory1(value1.type)) { - Operand value2 = pop(); - Operand value3 = pop(); - pushOperand(value1); - pushOperand(value3); - pushOperand(value2); - pushOperand(value1); - } else { - Operand value2 = pop(); - pushOperand(value1); - pushOperand(value2); - pushOperand(value1); + for(Environment env: stack.peek().environments()) { + assert env.operands.size() >= 2; + + Operand value1 = env.operands.pop(); + + if (allCategory1(value1.type)) { + Operand value2 = env.operands.pop(); + Operand value3 = env.operands.pop(); + env.operands.push(value1); + env.operands.push(value3); + env.operands.push(value2); + env.operands.push(value1); + } else { + Operand value2 = env.operands.pop(); + env.operands.push(value1); + env.operands.push(value2); + env.operands.push(value1); + } } } @@ -1323,20 +1407,22 @@ private void dupX2Ins() { * it duplicates just the first value. */ private void dup2Ins() { - assert sizeOfOperandStack() >= 2; - - Operand value1 = pop(); - Operand value2 = pop(); - - if (allCategory1(value1.type, value2.type)) { - pushOperand(value2); - pushOperand(value1); - pushOperand(value2); - pushOperand(value1); - } else { - pushOperand(value2); - pushOperand(value1); - pushOperand(value1); + for(Environment env: stack.peek().environments()) { + assert env.operands.size() >= 2; + + Operand value1 = env.operands.pop(); + Operand value2 = env.operands.pop(); + + if (allCategory1(value1.type, value2.type)) { + env.operands.push(value2); + env.operands.push(value1); + env.operands.push(value2); + env.operands.push(value1); + } else { + env.operands.push(value2); + env.operands.push(value1); + env.operands.push(value1); + } } } @@ -1345,23 +1431,25 @@ private void dup2Ins() { * values down, depending on the type category of the values. */ private void dup2X1Ins() { - assert sizeOfOperandStack() >= 3; - - Operand value1 = pop(); - Operand value2 = pop(); - Operand value3 = pop(); - - if (allCategory1(value1.type, value2.type, value3.type)) { - pushOperand(value2); - pushOperand(value1); - pushOperand(value3); - pushOperand(value2); - pushOperand(value1); - } else if ((allCategory2(value1.type)) && allCategory1(value2.type)) { - pushOperand(value3); - pushOperand(value1); - pushOperand(value2); - pushOperand(value1); + for(Environment env: stack.peek().environments()) { + assert env.operands.size() >= 3; + + Operand value1 = env.operands.pop(); + Operand value2 = env.operands.pop(); + Operand value3 = env.operands.pop(); + + if (allCategory1(value1.type, value2.type, value3.type)) { + env.operands.push(value2); + env.operands.push(value1); + env.operands.push(value3); + env.operands.push(value2); + env.operands.push(value1); + } else if ((allCategory2(value1.type)) && allCategory1(value2.type)) { + env.operands.push(value3); + env.operands.push(value1); + env.operands.push(value2); + env.operands.push(value1); + } } } @@ -1370,51 +1458,54 @@ private void dup2X1Ins() { * four values down */ private void dup2X2Ins() { - assert sizeOfOperandStack() >= 4; - - Operand value1 = pop(); - Operand value2 = pop(); - Operand value3 = pop(); - Operand value4 = pop(); - - if (allCategory1(value1.type, value2.type, value3.type, value4.type)) { - pushOperand(value2); - pushOperand(value1); - pushOperand(value4); - pushOperand(value3); - pushOperand(value2); - pushOperand(value1); - } else if ((allCategory2(value1.type)) && allCategory1(value2.type, value3.type)) { - pushOperand(value4); - pushOperand(value1); - pushOperand(value3); - pushOperand(value2); - pushOperand(value1); - } else if (allCategory1(value1.type, value2.type) && (allCategory2(value3.type))) { - pushOperand(value4); - pushOperand(value2); - pushOperand(value1); - pushOperand(value3); - pushOperand(value2); - pushOperand(value1); - } else if ((!allCategory2(value1.type, value2.type))) { - pushOperand(value4); - pushOperand(value3); - pushOperand(value1); - pushOperand(value2); - pushOperand(value1); + for(Environment env: stack.peek().environments()) { + assert env.operands.size() >= 4; + + Operand value1 = env.operands.pop(); + Operand value2 = env.operands.pop(); + Operand value3 = env.operands.pop(); + Operand value4 = env.operands.pop(); + + if (allCategory1(value1.type, value2.type, value3.type, value4.type)) { + env.operands.push(value2); + env.operands.push(value1); + env.operands.push(value4); + env.operands.push(value3); + env.operands.push(value2); + env.operands.push(value1); + } else if ((allCategory2(value1.type)) && allCategory1(value2.type, value3.type)) { + env.operands.push(value4); + env.operands.push(value1); + env.operands.push(value3); + env.operands.push(value2); + env.operands.push(value1); + } else if (allCategory1(value1.type, value2.type) && (allCategory2(value3.type))) { + env.operands.push(value4); + env.operands.push(value2); + env.operands.push(value1); + env.operands.push(value3); + env.operands.push(value2); + env.operands.push(value1); + } else if ((!allCategory2(value1.type, value2.type))) { + env.operands.push(value4); + env.operands.push(value3); + env.operands.push(value1); + env.operands.push(value2); + env.operands.push(value1); + } } - } private void swapIns() { - assert sizeOfOperandStack() >= 2; + for(Environment env: stack.peek().environments()) { + assert env.operands.size() >= 2; - Operand value1 = pop(); - Operand value2 = pop(); + Operand value1 = env.operands.pop(); + Operand value2 = env.operands.pop(); - pushOperand(value1); - pushOperand(value2); + env.operands.push(value1); + env.operands.push(value2); + } } /* @@ -1431,27 +1522,35 @@ private void getStaticIns(String owner, String field, String descriptor) { Type fieldType = type(descriptor); Expression fieldRef = Expression.fieldRef(owner.replace("/", "."), fieldType, field); - addInstruction(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); - pushOperand(new Operand(newLocal)); + env.operands.push(new Operand(newLocal)); + } } private void putStaticIns(String owner, String field, String descriptor) { - Operand value = pop(); FieldSignature signature = FieldSignature.fieldSignature(owner, type(descriptor), field); - addInstruction(assignmentStmt(Variable.staticFieldRef(signature), Expression.immediate(value.immediate))); + + for(Environment env: stack.peek().environments()) { + Operand value = env.operands.pop(); + env.instructions.add(assignmentStmt(Variable.staticFieldRef(signature), Expression.immediate(value.immediate))); + } } private void putFieldIns(String owner, String field, String descriptor) { - Operand value = pop(); - Operand operand = pop(); + FieldSignature signature = FieldSignature.fieldSignature(owner, type(descriptor), field); - String reference = ((Immediate.c_local) operand.immediate).localName; + for(Environment env: stack.peek().environments()) { + Operand value = env.operands.pop(); + Operand operand = env.operands.pop(); + + String reference = ((Immediate.c_local) operand.immediate).localName; - FieldSignature signature = FieldSignature.fieldSignature(owner, type(descriptor), field); - addInstruction( - assignmentStmt(Variable.fieldRef(reference, signature), Expression.immediate(value.immediate))); + env.instructions.add( + assignmentStmt(Variable.fieldRef(reference, signature), Expression.immediate(value.immediate))); + } } /* @@ -1465,18 +1564,22 @@ private void putFieldIns(String owner, String field, String descriptor) { * @param descriptor use to compute the field's type. */ private void getFieldIns(String owner, String field, String descriptor) { - Immediate instance = pop().immediate; - LocalVariableDeclaration newLocal = createLocal(descriptor); Type fieldType = type(descriptor); - Expression fieldRef = Expression.localFieldRef(((Immediate.c_local) instance).localName, owner, fieldType, - field); + for(Environment env: stack.peek().environments()) { + + Immediate instance = env.operands.pop().immediate; - addInstruction(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); - pushOperand(new Operand(newLocal)); + Expression fieldRef = Expression.localFieldRef(((Immediate.c_local) instance).localName, owner, fieldType, + field); + + env.instructions.add(Statement.assign(Variable.localVariable(newLocal.local), fieldRef)); + + env.operands.push(new Operand(newLocal)); + } } private LocalVariableDeclaration createLocal(String descriptor) { @@ -1509,7 +1612,9 @@ private boolean allCategory2(Type... types) { } private void pushConstantValue(Type type, Immediate immediate) { - pushOperand(new Operand(type, immediate)); + for(Environment env: stack.peek().environments()) { + env.operands.push(new Operand(type, immediate)); + } } private void createNewArrayIns(int aType) { @@ -1561,17 +1666,16 @@ public void initFormalArgs(boolean staticMethod, Type classType, boolean emptyLo idx++; } } - if (!staticMethod) { - addInstruction(Statement.identity(LOCAL_NAME_FOR_IMPLICIT_PARAMETER, IMPLICIT_PARAMETER_NAME, classType)); // init - // the - // implicit - // parameter - } - int idx = 0; - for (Type t : formals) { - addInstruction(Statement.identity(LOCAL_VARIABLE_PARAMETER_PREFIX + (idx + 1), - LOCAL_PARAMETER_PREFIX + idx, t)); - idx++; + for(Environment env: stack.peek().environments()) { + if (!staticMethod) { + env.instructions.add(Statement.identity(LOCAL_NAME_FOR_IMPLICIT_PARAMETER, IMPLICIT_PARAMETER_NAME, classType)); + } + int idx = 0; + for (Type t : formals) { + env.instructions.add(Statement.identity(LOCAL_VARIABLE_PARAMETER_PREFIX + (idx + 1), + LOCAL_PARAMETER_PREFIX + idx, t)); + idx++; + } } } diff --git a/src/main/java/lang/jimple/internal/Environment.java b/src/main/java/lang/jimple/internal/Environment.java new file mode 100644 index 00000000..6fbf221d --- /dev/null +++ b/src/main/java/lang/jimple/internal/Environment.java @@ -0,0 +1,17 @@ +package lang.jimple.internal; + +import lang.jimple.internal.generated.Statement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class Environment { + Stack operands; + List instructions; + + public Environment() { + operands = new Stack<>(); + instructions = new ArrayList<>(); + } +} diff --git a/src/main/java/lang/jimple/internal/InstructionFlow.java b/src/main/java/lang/jimple/internal/InstructionFlow.java index c8efa419..ed476f57 100644 --- a/src/main/java/lang/jimple/internal/InstructionFlow.java +++ b/src/main/java/lang/jimple/internal/InstructionFlow.java @@ -1,16 +1,16 @@ package lang.jimple.internal; import java.util.Collection; +import java.util.List; import lang.jimple.internal.generated.Statement; public interface InstructionFlow { - - public void push(Operand operand); - public Operand pop(); - public void addInstruction(Statement stmt); - public void clearOperandStack(); - public int sizeOfOperandStack(); - public Collection merge(); - + Collection merge(); + boolean matchMergePoint(String label); + List environments(); + void nextBranch(); + void notifyGotoStmt(String label); + boolean isBranch(); + boolean readyToMerge(String label); } diff --git a/src/main/java/lang/jimple/internal/SingleInstructionFlow.java b/src/main/java/lang/jimple/internal/SingleInstructionFlow.java index a57f8456..d4cc5fb1 100644 --- a/src/main/java/lang/jimple/internal/SingleInstructionFlow.java +++ b/src/main/java/lang/jimple/internal/SingleInstructionFlow.java @@ -9,38 +9,43 @@ public class SingleInstructionFlow implements InstructionFlow { - Stack operands; - List instructions; + Environment environment; public SingleInstructionFlow() { - operands = new Stack<>(); - instructions = new ArrayList<>(); + environment = new Environment(); } - - public void push(Operand operand) { - operands.push(operand); - } - - public Operand pop() { - return operands.pop(); - } - - public void addInstruction(Statement stmt) { - instructions.add(stmt); + + @Override + public List environments() { + List res = new ArrayList<>(); + res.add(environment); + return res; } - - public void clearOperandStack() { - operands.clear(); + + @Override + public void nextBranch() { } + + @Override + public void notifyGotoStmt(String label) { } + + @Override + public boolean isBranch() { + return false; } @Override - public int sizeOfOperandStack() { - return operands.size(); + public boolean readyToMerge(String label) { + return true; } @Override public Collection merge() { - return new ArrayList<>(instructions); + return new ArrayList<>(environment.instructions); + } + + @Override + public boolean matchMergePoint(String label) { + return true; } } diff --git a/src/test/.DS_Store b/src/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4ea07896c030c9aeca3a36dfdab8cddeed3a00a1 GIT binary patch literal 6148 zcmeHK!EVz)5S>lab{&Ms0jWLug2bVRR1kuMkgT*EdaGmv2SBZzMAXQ5tJrA-A;`Z$ z|Dd1JFW__F&F-dB(jqPu0yHDdzS-HCvGzIH^$?NjPlmfhZ6eZ8#zuhQ2H|zqYtrzZ zb)e!J2e}!fxk)kSf+BxE1N`oq^nnsOqh#g%J;U0=A6D!}HfW5vk_H&_mDr1w*Z{F3 z#2T8w8nC^bp|*aXkxt7~|9iSjPxGv-I-T#TvDRGQ*wnhETX$RU;uABCtE8Hg{bc-x zXNO63l6w24G5M99q_48k^r(G*&lFXX6{E3D&W0m|ynUS&Lo@B0Nii&Ko!BjC9q8bw zy*-LPQIAt($81H!~k82Hy2;PWAbGDaS2hxX{eU|RrS z6K*T8?WaF5WCt+vSUZFVqFgG_r7GWIDBn3KmyY$w$JY*BIw|{P)bUSNzC%&I@lc@+ zClxuAQ5X;gmKj)c(>CA#FMi$sFDJ=N7!U^jD+W|^Ki= c = (String l, String r) -> l.compareTo(r); + + System.out.println(c.compare("hello", "world")); + } + +} diff --git a/src/test/java/samples/operators/IntOps.java b/src/test/java/samples/operators/IntOps.java index cd37b9d0..6e3ba577 100644 --- a/src/test/java/samples/operators/IntOps.java +++ b/src/test/java/samples/operators/IntOps.java @@ -137,17 +137,17 @@ public static void main(String[] args) throws InvocationTargetException, Illegal // System.out.println(result); // } - public void lessOrEqualsThan() { - int a = 5; - int b = 5; - boolean result = (a <= b); - System.out.println(result); - } +// public void lessOrEqualsThan() { +// int a = 5; +// int b = 5; +// boolean result = (a <= b); +// System.out.println(result); +// } public void ternaryExpression() { int a = 5; int b = 5; - int result = (a == b) ? 1 : 0; + int result = (a == b) ? 1 : 0; System.out.println(result); } } diff --git a/src/test/rascal/TestSuite.rsc b/src/test/rascal/TestSuite.rsc new file mode 100644 index 00000000..aaa58125 --- /dev/null +++ b/src/test/rascal/TestSuite.rsc @@ -0,0 +1,28 @@ +module TestSuite + +import TestAvailableExpressions; + +import IO; +import List; + +data TestCase = TestCase(str name, bool () function); + +list[TestCase] tcs = [TestCase("TestAvailableExpressions", testAvailableExpressions)]; + + +public void main(list[str] _) { + int count = 0; + list[str] errors = []; + + while(count < size(tcs)) { + try { + res = tcs[count].function(); + if(! res) { + errors += "test case failed"; + } + } + catch: errors += "foo"; + count = count + 1; + } + println(errors); +} \ No newline at end of file diff --git a/src/test/resources/.DS_Store b/src/test/resources/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a6a0c8c0ba461893e593dd6b79bcdac56bc40d4e GIT binary patch literal 6148 zcmeHK!H&}~5FK}0aJxeEfLM;XAaPivR$H+LgcOzKuqTj$-~ebhA%zVJanz(#P>S*w z@C$qipTOt98{4e5TY6g|w3>;=Z*0$V5!;TL>kW6>Z16IaX(&J*<^my zzwyu%b(|HGsU>IW1Sv0{XGLn}V>2t#%8nDc4z0Vod(^+VSPXW9z0q*F8!Yzs5s&un zEtg%rb9?yU@c8}5Pm9mXFJJ9+NZ}K() + { + org.slf4j.MDC r0; + + r0 := @this: org.slf4j.MDC; + + specialinvoke r0.()>(); + + return; + } + + public static void put(java.lang.String, java.lang.String) throws java.lang.IllegalArgumentException + { + java.lang.String r0, r2; + org.slf4j.spi.MDCAdapter $r1, $r3; + java.lang.IllegalStateException $r4; + java.lang.IllegalArgumentException $r5; + + r0 := @parameter0: java.lang.String; + + r2 := @parameter1: java.lang.String; + + if r0 != null goto label1; + + $r5 = new java.lang.IllegalArgumentException; + + specialinvoke $r5.(java.lang.String)>("key parameter cannot be null"); + + throw $r5; + + label1: + $r1 = ; + + if $r1 != null goto label2; + + $r4 = new java.lang.IllegalStateException; + + specialinvoke $r4.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); + + throw $r4; + + label2: + $r3 = ; + + interfaceinvoke $r3.(r0, r2); + + return; + } + + public static java.lang.String get(java.lang.String) throws java.lang.IllegalArgumentException + { + java.lang.String r0, $r3; + org.slf4j.spi.MDCAdapter $r1, $r2; + java.lang.IllegalStateException $r4; + java.lang.IllegalArgumentException $r5; + + r0 := @parameter0: java.lang.String; + + if r0 != null goto label1; + + $r5 = new java.lang.IllegalArgumentException; + + specialinvoke $r5.(java.lang.String)>("key parameter cannot be null"); + + throw $r5; + + label1: + $r1 = ; + + if $r1 != null goto label2; + + $r4 = new java.lang.IllegalStateException; + + specialinvoke $r4.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); + + throw $r4; + + label2: + $r2 = ; + + $r3 = interfaceinvoke $r2.(r0); + + return $r3; + } + + public static void remove(java.lang.String) throws java.lang.IllegalArgumentException + { + java.lang.String r0; + org.slf4j.spi.MDCAdapter $r1, $r2; + java.lang.IllegalStateException $r3; + java.lang.IllegalArgumentException $r4; + + r0 := @parameter0: java.lang.String; + + if r0 != null goto label1; + + $r4 = new java.lang.IllegalArgumentException; + + specialinvoke $r4.(java.lang.String)>("key parameter cannot be null"); + + throw $r4; + + label1: + $r1 = ; + + if $r1 != null goto label2; + + $r3 = new java.lang.IllegalStateException; + + specialinvoke $r3.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); + + throw $r3; + + label2: + $r2 = ; + + interfaceinvoke $r2.(r0); + + return; + } + + public static void clear() + { + org.slf4j.spi.MDCAdapter $r0, $r1; + java.lang.IllegalStateException $r2; + + $r0 = ; + + if $r0 != null goto label1; + + $r2 = new java.lang.IllegalStateException; + + specialinvoke $r2.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); + + throw $r2; + + label1: + $r1 = ; + + interfaceinvoke $r1.(); + + return; + } + + public static java.util.Map getCopyOfContextMap() + { + org.slf4j.spi.MDCAdapter $r0, $r1; + java.util.Map $r2; + java.lang.IllegalStateException $r3; + + $r0 = ; + + if $r0 != null goto label1; + + $r3 = new java.lang.IllegalStateException; + + specialinvoke $r3.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); + + throw $r3; + + label1: + $r1 = ; + + $r2 = interfaceinvoke $r1.(); + + return $r2; + } + + public static void setContextMap(java.util.Map) + { + org.slf4j.spi.MDCAdapter $r0, $r2; + java.util.Map r1; + java.lang.IllegalStateException $r3; + + r1 := @parameter0: java.util.Map; + + $r0 = ; + + if $r0 != null goto label1; + + $r3 = new java.lang.IllegalStateException; + + specialinvoke $r3.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); + + throw $r3; + + label1: + $r2 = ; + + interfaceinvoke $r2.(r1); + + return; + } + + public static org.slf4j.spi.MDCAdapter getMDCAdapter() + { + org.slf4j.spi.MDCAdapter $r0; + + $r0 = ; + + return $r0; + } + + static void () + { + org.slf4j.impl.StaticMDCBinder $r0, $r5; + org.slf4j.spi.MDCAdapter $r1; + java.lang.Exception $r2; + java.lang.StringBuffer $r3, $r4, $r7, $r8; + java.lang.String $r6, $r9, r11; + java.lang.NoClassDefFoundError $r10; + int $i0; + + = "http://www.slf4j.org/codes.html#no_static_mdc_binder"; + + = "http://www.slf4j.org/codes.html#null_MDCA"; + + label1: + $r0 = ; + + $r1 = virtualinvoke $r0.(); + + = $r1; + + label2: + goto label6; + + label3: + $r10 := @caughtexception; + + r11 = virtualinvoke $r10.(); + + if r11 == null goto label4; + + $i0 = virtualinvoke r11.("org/slf4j/impl/StaticMDCBinder"); + + if $i0 == -1 goto label4; + + staticinvoke ("Failed to load class \"org.slf4j.impl.StaticMDCBinder\"."); + + staticinvoke ("See http://www.slf4j.org/codes.html#no_static_mdc_binder for further details."); + + label4: + throw $r10; + + label5: + $r2 := @caughtexception; + + $r3 = new java.lang.StringBuffer; + + specialinvoke $r3.()>(); + + $r4 = virtualinvoke $r3.("Could not bind with an instance of class ["); + + $r5 = ; + + $r6 = virtualinvoke $r5.(); + + $r7 = virtualinvoke $r4.($r6); + + $r8 = virtualinvoke $r7.("]"); + + $r9 = virtualinvoke $r8.(); + + staticinvoke ($r9, $r2); + + label6: + return; + + catch java.lang.NoClassDefFoundError from label1 to label2 with label3; + catch java.lang.Exception from label1 to label2 with label5; + } +} diff --git a/src/test/resources/sootOutput/org/slf4j/MDC.class b/src/test/resources/sootOutput/org/slf4j/MDC.class new file mode 100644 index 0000000000000000000000000000000000000000..cbf117a5849233ffc8858754919df4b7b0412de5 GIT binary patch literal 2509 zcmbVNTXz#x7~Ll=&7D^ZyHuJUtU|6H9w94fdr3p>V!6>u2z<&mgWoUU3GfCG&8%n zN#x%H#}puiQ6@^ZMFS7 z0t4fj`vT`8NF}>q8lE>J8*_Hos?WNv?Z$CT;COUrcC#iOzinG_9H(&}xBwSES-G@QceBu?UtK)fk^mAk;%@l225K1>?k#Mu;0 z-qJ9Hqe;YYo{T7C>3K#|3XIS`f)G|t!`m23A&mG%a+o$jw<*QL*p9uvII z1o!hd-EA}^<#9vc@a;fR8a~8u3X}LqAX~7zW?i>zUsp2KH`;znH!QtvQNUJB>UJaK zXEg!J^047J(y9ww?nm=$%y z(=qITg{T|#nqdV5NnMSIoUW>7n4W!b>7t49g<_p`FJqCjB~sC=O%lhFh6M~C!7|wM z1LR8JVjs+X`b1#tHDFV2v)hrD--GQNw&_FpSa%H9=tvHteee?aHicCzYWNx}Dvv7X z3iBw~&f{{UU|YW2^cM_A;Mi`rcG&@WzG9sXtSOrsyWy2O6N}R&mP>uG^wckGc~!gy zn#xm)nsa5xek3)l{^3Z{$uG_pG5VLz2#}9l(b0u;AzF~IR ztb+x92q-#Aq4qF!WcQGWnPxb6IB-Ehe zS(2+aFwC1icR%uOjL-5@jBerFuh4(S?7i$3-YHJ}fm0LdcegMR`w2toE6;E({Q>{7 zFYmp;M4u&wvV|)s}JCxl<@kwx;RLTsGuMxfaop}oVPYk_4c_sbjHYzW< ze~zyNl*vx?1fRpf<)o4nqbL$ebfEl?X9M%qmGpyce5cI!yURYu_c8pk=Wm1_jw&n) z!MWYVBW?!iah1p^LatPle@~NREOOhMro`FMfx@ePgG@}_Rm4)6A&6yyP?gLa3}WIr z+5 Date: Mon, 8 Feb 2021 09:33:43 -0300 Subject: [PATCH 03/16] additional fix for positioning the goto statement when merging --- .../jimple/internal/BranchInstructionFlow.java | 17 ++++++++++++++++- .../java/lang/jimple/internal/Decompiler.java | 17 ++++++----------- .../lang/jimple/internal/InstructionFlow.java | 2 +- .../jimple/internal/SingleInstructionFlow.java | 4 +++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java index f7822168..33189707 100644 --- a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java +++ b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java @@ -18,6 +18,8 @@ public class BranchInstructionFlow implements InstructionFlow { private String mergeStatement; private BranchState status; + + private Statement gotoMergeStmt; enum BranchState { LEFT, @@ -40,6 +42,11 @@ public Collection merge() { res.add(Statement.ifStmt(condition, targetStatement)); res.addAll(left.instructions); + + if(gotoMergeStmt != null) { + res.add(gotoMergeStmt); + } + res.addAll(right.instructions); return res; @@ -68,9 +75,17 @@ public List environments() { } @Override - public void notifyGotoStmt(String label) { + public void notifyGotoStmt(Statement stmt, String label) { if(status.equals(BranchState.LEFT)) { mergeStatement = label; + gotoMergeStmt = stmt; + } + else if(status.equals(BranchState.RIGHT)) { + right.instructions.add(stmt); + } + else if(status.equals(BranchState.ReadyToMerge)) { + left.instructions.add(stmt); + right.instructions.add(stmt); } } diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index 3994983c..48fed104 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -312,8 +312,8 @@ public List instructions() { return new ArrayList<>(stack.peek().merge()); } - private void notifyGotoStmt(String label) { - stack.peek().notifyGotoStmt(label); + private void notifyGotoStmt(Statement stmt, String label) { + stack.peek().notifyGotoStmt(stmt, label); } private void notifyReturn() { @@ -343,16 +343,14 @@ public void visitLabel(Label label) { referencedLabels.add(label.toString()); } } - + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.label(label.toString())); + } if(isBranch() && stack.peek().matchMergePoint(label.toString())) { - for(Environment env: stack.peek().environments()) { - env.instructions.add(Statement.label(label.toString())); - } nextBranch(); } else if(readyToMerge(label.toString()) && stack.size() > 1) { List stmts = new ArrayList<>(stack.pop().merge()); - stack.peek().environments().get(0).instructions.addAll(stmts); } } @@ -945,10 +943,7 @@ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) @Override public void visitJumpInsn(int opcode, Label label) { if (opcode == Opcodes.GOTO) { - for(Environment env: stack.peek().environments()) { - env.instructions.add(Statement.gotoStmt(label.toString())); - } - notifyGotoStmt(label.toString()); // TODO: investigate this decision here. + notifyGotoStmt(Statement.gotoStmt(label.toString()), label.toString()); // TODO: investigate this decision here. } else if (opcode == Opcodes.JSR) { throw RuntimeExceptionFactory.illegalArgument(vf.string("unsupported instruction JSR" + opcode), null, null); diff --git a/src/main/java/lang/jimple/internal/InstructionFlow.java b/src/main/java/lang/jimple/internal/InstructionFlow.java index ed476f57..2c9160f5 100644 --- a/src/main/java/lang/jimple/internal/InstructionFlow.java +++ b/src/main/java/lang/jimple/internal/InstructionFlow.java @@ -10,7 +10,7 @@ public interface InstructionFlow { boolean matchMergePoint(String label); List environments(); void nextBranch(); - void notifyGotoStmt(String label); + void notifyGotoStmt(Statement stmt, String label); boolean isBranch(); boolean readyToMerge(String label); } diff --git a/src/main/java/lang/jimple/internal/SingleInstructionFlow.java b/src/main/java/lang/jimple/internal/SingleInstructionFlow.java index d4cc5fb1..879de434 100644 --- a/src/main/java/lang/jimple/internal/SingleInstructionFlow.java +++ b/src/main/java/lang/jimple/internal/SingleInstructionFlow.java @@ -26,7 +26,9 @@ public List environments() { public void nextBranch() { } @Override - public void notifyGotoStmt(String label) { } + public void notifyGotoStmt(Statement stmt, String label) { + environment.instructions.add(stmt); + } @Override public boolean isBranch() { From 9573f2b4cc23a7a2a07e6f75e8c21279ecde5009 Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Mon, 8 Feb 2021 19:17:07 -0300 Subject: [PATCH 04/16] major refactoring / bug fixing done --- .../java/lang/jimple/internal/Decompiler.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index 48fed104..b10fdbda 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -210,11 +210,11 @@ private void visitMethod(MethodNode mn) { mn.instructions.accept(insVisitor); // TODO: we commented this line because we want to - // solve this issue using a Jimple transformation. - // we will keep the commented implementation here just while - // we review the new strategy. + // solve this issue using a Jimple transformation. + // we will keep the commented implementation here just while + // we review the new strategy. // - // insVisitor.clearUnusedLabelInstructions(); + // insVisitor.clearUnusedLabelInstructions(); stmts = insVisitor.instructions(); @@ -343,15 +343,20 @@ public void visitLabel(Label label) { referencedLabels.add(label.toString()); } } - for(Environment env: stack.peek().environments()) { - env.instructions.add(Statement.label(label.toString())); - } + if(isBranch() && stack.peek().matchMergePoint(label.toString())) { nextBranch(); } else if(readyToMerge(label.toString()) && stack.size() > 1) { List stmts = new ArrayList<>(stack.pop().merge()); stack.peek().environments().get(0).instructions.addAll(stmts); + stack.peek().environments().get(0).instructions.add(Statement.label(label.toString())); + referencedLabels.add(label.toString()); + } + else { + for(Environment env: stack.peek().environments()) { + env.instructions.add(Statement.label(label.toString())); + } } } From 6d43327df8ad77a84c82f2f9737ade04857d9462 Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Tue, 9 Feb 2021 10:17:12 -0300 Subject: [PATCH 05/16] fix invoke dynamic when the return type is different than void --- src/main/java/lang/jimple/internal/Decompiler.java | 8 +++++++- src/test/java/lang/jimple/internal/TestDecompiler.java | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index b10fdbda..594bbb33 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -894,7 +894,13 @@ public void visitInvokeDynamicInsn(String name, String descriptor, Handle bsmh, } InvokeExp exp = InvokeExp.dynamicInvoke(bootstrapMethod, bootstrapArgs, method, args); - env.instructions.add(Statement.invokeStmt(exp)); + if (methodType.equals(Type.TVoid())) { + env.instructions.add(Statement.invokeStmt(exp)); + } else { + LocalVariableDeclaration local = createLocal(methodType); + env.instructions.add(assignmentStmt(Variable.localVariable(local.local), Expression.invokeExp(exp))); + env.operands.push(new Operand(local)); + } } super.visitInvokeDynamicInsn(name, descriptor, bsmh, bootstrapMethodArguments); } diff --git a/src/test/java/lang/jimple/internal/TestDecompiler.java b/src/test/java/lang/jimple/internal/TestDecompiler.java index 88fd2ce0..875a843f 100644 --- a/src/test/java/lang/jimple/internal/TestDecompiler.java +++ b/src/test/java/lang/jimple/internal/TestDecompiler.java @@ -14,8 +14,6 @@ import io.usethesource.vallang.impl.persistent.ValueFactory; public class TestDecompiler { - - @Test public void decompileClassWithFields() { try { From 3f39cab1f066d13b4eeb0a43e1cb33a618b8d56d Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Tue, 9 Feb 2021 10:37:22 -0300 Subject: [PATCH 06/16] mark two test cases as ignore.... the last commit broke something --- src/test/java/lang/jimple/internal/TestDecompiler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/lang/jimple/internal/TestDecompiler.java b/src/test/java/lang/jimple/internal/TestDecompiler.java index 875a843f..7a08b973 100644 --- a/src/test/java/lang/jimple/internal/TestDecompiler.java +++ b/src/test/java/lang/jimple/internal/TestDecompiler.java @@ -178,7 +178,7 @@ public void decompileAndroidClass() { } } - @Test + @Ignore public void decompileSwitchCaseSample() { try { File classFile = new File("./target/test-classes/samples/SwitchCaseSample.class"); @@ -196,7 +196,7 @@ public void decompileSwitchCaseSample() { } } - @Test + @Ignore public void decompileControlStatements() { try { File classFile = new File("./target/test-classes/samples/ControlStatements.class"); From 909cd7beb7937c5b58f16d5f4f367530983aba9d Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Tue, 9 Feb 2021 18:38:19 -0300 Subject: [PATCH 07/16] fix issue with the Table Switch decompiler --- .../java/lang/jimple/internal/Decompiler.java | 16 +++++++--------- .../lang/jimple/internal/TestDecompiler.java | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index 594bbb33..168a6b55 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -935,17 +935,15 @@ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { @Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { + List caseStmts = new ArrayList<>(); + for (Label label : labels) { + caseStmts.add(CaseStmt.caseOption(label.getOffset(), label.toString())); + } + if (dflt != null) { + caseStmts.add(CaseStmt.defaultOption(dflt.toString())); + } for(Environment env: stack.peek().environments()) { Immediate key = env.operands.pop().immediate; - List caseStmts = new ArrayList<>(); - - for (Label label : labels) { - caseStmts.add(CaseStmt.caseOption(label.getOffset(), label.toString())); - } - - if (dflt != null) { - caseStmts.add(CaseStmt.defaultOption(dflt.toString())); - } env.instructions.add(Statement.tableSwitch(key, min, max, caseStmts)); } super.visitTableSwitchInsn(min, max, dflt, labels); diff --git a/src/test/java/lang/jimple/internal/TestDecompiler.java b/src/test/java/lang/jimple/internal/TestDecompiler.java index 7a08b973..ef31412e 100644 --- a/src/test/java/lang/jimple/internal/TestDecompiler.java +++ b/src/test/java/lang/jimple/internal/TestDecompiler.java @@ -178,7 +178,7 @@ public void decompileAndroidClass() { } } - @Ignore + @Test public void decompileSwitchCaseSample() { try { File classFile = new File("./target/test-classes/samples/SwitchCaseSample.class"); @@ -196,7 +196,7 @@ public void decompileSwitchCaseSample() { } } - @Ignore + @Test public void decompileControlStatements() { try { File classFile = new File("./target/test-classes/samples/ControlStatements.class"); From 5f3c8419c2e71a725635d187ade3280965d00b80 Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Wed, 10 Feb 2021 13:54:42 -0300 Subject: [PATCH 08/16] pretty print of dynamic invoke --- .../lang/jimple/util/JPrettyPrinter.rsc | 38 +++++++++++-------- .../lang/jimple/tests/TestPrettyPrinter.rsc | 2 +- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc b/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc index a759716f..9bb56dfb 100644 --- a/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc +++ b/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc @@ -28,6 +28,7 @@ public str prettyPrint(Value::stringValue(String sv)) = "\"\""; public str prettyPrint(Value::booleanValue(bool bl)) = ""; public str prettyPrint(Value::classValue(str name)) = name; public str prettyPrint(Value::methodValue(Type returnType, list[Type] formals)) = "TODO"; +public str prettyPrint(Value::methodHandle(MethodSignature methodSig)) = "TODO"; public str prettyPrint(Value::fieldHandle(FieldSignature fieldSig)) = "TODO"; public str prettyPrint(Value::nullValue()) = "null"; @@ -183,22 +184,29 @@ public str prettyPrint(list[Immediate] args) { return text; } -public str prettyPrint(InvokeExp invoke) { - switch(invoke) { - case specialInvoke(local, sig, args): - return "specialinvoke .\<\>()"; - case virtualInvoke(local, sig, args): - return "virtualinvoke .\<\>()"; - case interfaceInvoke(local, sig, args): - return "interfaceinvoke .\<\>()"; - case staticMethodInvoke(sig, args): - return "staticinvoke \<\>()"; - case dynamicInvoke(bsmSig, bsmArgs, sig, args): - return "dynamicinvoke TODO"; - default: return "error"; - } - } +public str prettyPrint(specialInvoke(local, sig, args)) = + "specialinvoke .\<\>()"; + +public str prettyPrint(virtualInvoke(local, sig, args)) = + "virtualinvoke .\<\>()"; + +public str prettyPrint(interfaceInvoke(local, sig, args)) = + "interfaceinvoke .\<\>()"; + +public str prettyPrint(staticMethodInvoke(sig, args)) = + "staticinvoke \<\>()"; + +public str prettyPrint(dynamicInvoke(bsmSig, bsmArgs, sig, args)) = + "dynamicinvoke () \<\>()"; + + +/* + Due to problems in accessing fields of abstract parameters this was done: NoSuchField("methodName") +*/ +str dynamicPrettyPrint(MethodSignature::methodSignature(_, Type returnType, Name methodName, list[Type] formals)) = + "\"\" \< ()\>"; + /* Functions for printing ClassOrInterfaceDeclaration and its related upper parts. diff --git a/src/test/rascal/lang/jimple/tests/TestPrettyPrinter.rsc b/src/test/rascal/lang/jimple/tests/TestPrettyPrinter.rsc index 9cf89aaa..d19bb5b4 100644 --- a/src/test/rascal/lang/jimple/tests/TestPrettyPrinter.rsc +++ b/src/test/rascal/lang/jimple/tests/TestPrettyPrinter.rsc @@ -94,4 +94,4 @@ test bool testProcessAllFiles() { writeFile(|file:///tmp/jimpleframework/.jimple|, x[k]); } return true; -} \ No newline at end of file +} From fa28eda08086bc579954593e260a253bbb0142e9 Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Marques Silva Date: Fri, 12 Feb 2021 06:00:34 -0300 Subject: [PATCH 09/16] Update README.md --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c0ee340d..6bad7a4c 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,20 @@ A Rascal implementation of the Jimple framework. The current version supports: * parsing Java Byte Code into a JIMPLE representation. * JIMPLE code optmization constructs. * a framework for dataflow analysis. - + +### Requirements + +* Java ? +* Maven +* Rascal +* Eclipse IDE +* Lombok + +### Setting up your requirements + + 1. Make sure Eclipse is running on Java ?. Also, you need to setup your PATH to use Java ? when using Maven. + 2. Install Lombok into Eclipse IDE. https://projectlombok.org/setup/eclipse + +### Installation Procedure + From 01d6b214bd8e395417db635327f8243076059d63 Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Fri, 12 Feb 2021 17:05:29 -0300 Subject: [PATCH 10/16] fix a bug when decompiling while statements --- src/main/java/lang/jimple/internal/Decompiler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index 168a6b55..2ba944b2 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -289,6 +289,8 @@ class InstructionSetVisitor extends org.objectweb.asm.MethodVisitor { HashMap localVariables; int locals; + Set visitedLabels = new HashSet<>(); + // we use this set to keep track of the referenced labels. // afterwards we can remove labeled instructions that are // not refered to in the bytecode. @@ -336,6 +338,7 @@ private boolean readyToMerge(String label) { @Override public void visitLabel(Label label) { + visitedLabels.add(label.toString()); if (catchClauses.containsKey(label.toString())) { for(Environment env: stack.peek().environments()) { CatchClause c = catchClauses.get(label.toString()); @@ -1022,7 +1025,12 @@ public void visitJumpInsn(int opcode, Label label) { throw RuntimeExceptionFactory.illegalArgument(vf.string("invalid instruction " + opcode), null, null); } - stack.push(new BranchInstructionFlow(exp, label.toString())); + if(visitedLabels.contains(label.toString())) { + env.instructions.add(Statement.ifStmt(exp, label.toString())); + } + else { + stack.push(new BranchInstructionFlow(exp, label.toString())); + } } } referencedLabels.add(label.toString()); From 7c7203fc38b3723bb9022bad0f1b83b8a0aa4e7d Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Fri, 12 Feb 2021 17:44:56 -0300 Subject: [PATCH 11/16] fix the setup of labels when merging branches --- src/main/java/lang/jimple/internal/BranchInstructionFlow.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java index 33189707..a29adb7f 100644 --- a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java +++ b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java @@ -47,7 +47,9 @@ public Collection merge() { res.add(gotoMergeStmt); } + res.add(Statement.label(targetStatement)); res.addAll(right.instructions); + res.add(Statement.label(mergeStatement)); return res; } @@ -105,7 +107,7 @@ public boolean isBranch() { @Override public boolean readyToMerge(String label) { - this.targetStatement = label; + // this.targetStatement = label; return status.equals(BranchState.ReadyToMerge); } } \ No newline at end of file From 8795a2f94f6fae1222a6185ac9089732e216d7cf Mon Sep 17 00:00:00 2001 From: Rodrigo Bonifacio Date: Mon, 15 Feb 2021 09:12:29 -0300 Subject: [PATCH 12/16] additional fixes into the Decompiler --- .../internal/BranchInstructionFlow.java | 25 ++++++++++++++--- .../java/lang/jimple/internal/Decompiler.java | 1 + .../lang/jimple/internal/TestDecompiler.java | 21 ++++++++++++++- src/test/java/samples/IfStatement.java | 27 +++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/test/java/samples/IfStatement.java diff --git a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java index a29adb7f..9e07e24c 100644 --- a/src/main/java/lang/jimple/internal/BranchInstructionFlow.java +++ b/src/main/java/lang/jimple/internal/BranchInstructionFlow.java @@ -49,7 +49,10 @@ public Collection merge() { res.add(Statement.label(targetStatement)); res.addAll(right.instructions); - res.add(Statement.label(mergeStatement)); + + if(mergeStatement != null) { + res.add(Statement.label(mergeStatement)); + } return res; } @@ -71,7 +74,14 @@ public List environments() { switch(status) { case LEFT: res.add(left); break; case RIGHT: res.add(right); break; - case ReadyToMerge: res.add(left); res.add(right); + case ReadyToMerge: + if(mergeStatement != null) { + res.add(left); + res.add(right); + } + else { + res.add(left); + } } return res; } @@ -94,7 +104,15 @@ else if(status.equals(BranchState.ReadyToMerge)) { @Override public void nextBranch() { switch(status) { - case LEFT: status = BranchState.RIGHT; break; + case LEFT: + if(mergeStatement != null) { + status = BranchState.RIGHT; + } + else { + left.instructions.add(Statement.label(targetStatement)); + status = BranchState.ReadyToMerge; + } + break; case RIGHT: status = BranchState.ReadyToMerge; break; case ReadyToMerge: // } @@ -107,7 +125,6 @@ public boolean isBranch() { @Override public boolean readyToMerge(String label) { - // this.targetStatement = label; return status.equals(BranchState.ReadyToMerge); } } \ No newline at end of file diff --git a/src/main/java/lang/jimple/internal/Decompiler.java b/src/main/java/lang/jimple/internal/Decompiler.java index 2ba944b2..60ac3b81 100644 --- a/src/main/java/lang/jimple/internal/Decompiler.java +++ b/src/main/java/lang/jimple/internal/Decompiler.java @@ -1106,6 +1106,7 @@ private void loadIns(int var) { */ private void storeIns(int var) { LocalVariableDeclaration local = findLocalVariable(var); + for (Environment env : stack.peek().environments()) { Immediate immediate = env.operands.pop().immediate; env.instructions.add(assignmentStmt(Variable.localVariable(local.local), Expression.immediate(immediate))); diff --git a/src/test/java/lang/jimple/internal/TestDecompiler.java b/src/test/java/lang/jimple/internal/TestDecompiler.java index ef31412e..5aabe2c0 100644 --- a/src/test/java/lang/jimple/internal/TestDecompiler.java +++ b/src/test/java/lang/jimple/internal/TestDecompiler.java @@ -14,7 +14,26 @@ import io.usethesource.vallang.impl.persistent.ValueFactory; public class TestDecompiler { - @Test + @Test + public void decompileClassWithIfStatement() { + try { + File classFile = new File("./target/test-classes/samples/IfStatement.class"); + assertNotNull(classFile); + + IValueFactory vf = ValueFactory.getInstance(); + Decompiler decompiler = new Decompiler(vf); + IConstructor c = decompiler.decompile(new FileInputStream(classFile), null); + + assertNotNull(c); + } + catch(Exception e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } + } + + + @Test public void decompileClassWithFields() { try { File classFile = new File("./target/test-classes/samples/ClassWithFields.class"); diff --git a/src/test/java/samples/IfStatement.java b/src/test/java/samples/IfStatement.java new file mode 100644 index 00000000..39eb12a8 --- /dev/null +++ b/src/test/java/samples/IfStatement.java @@ -0,0 +1,27 @@ +package samples; + +public class IfStatement { + + public static void foo(int x) { + if(x > 0) { + x = x + 1; + } + System.out.println(x); + } + + public static void blah(int x, int y) { + if(x < 0) { + return; + } + System.out.println(x + y); + } + + public static void ugly(int x, int y) { + int z = 0; + if(x < 0) { + z = y > 10 ? x + y : x; + } + System.out.println(z); + } + +} From a8400a44b4c5d4859ab22550e5cf9a4a494a6359 Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Mon, 22 Feb 2021 17:57:02 -0300 Subject: [PATCH 13/16] remove constant propagator until FlowGraph is fixed, fix pp for interfaces --- src/main/rascal/lang/jimple/core/Context.rsc | 2 +- .../lang/jimple/toolkit/PrettyPrinter.rsc | 3 +- .../lang/jimple/internal/TestDecompiler.java | 1 + .../java/samples/arrays/ArrayExample.java | 28 ++ .../resources/sootOutput/org.slf4j.MDC.jimple | 279 ------------------ .../resources/sootOutput/org/slf4j/MDC.class | Bin 2509 -> 0 bytes 6 files changed, 32 insertions(+), 281 deletions(-) create mode 100644 src/test/java/samples/arrays/ArrayExample.java delete mode 100644 src/test/resources/sootOutput/org.slf4j.MDC.jimple delete mode 100644 src/test/resources/sootOutput/org/slf4j/MDC.class diff --git a/src/main/rascal/lang/jimple/core/Context.rsc b/src/main/rascal/lang/jimple/core/Context.rsc index 751dff83..3e506b9c 100644 --- a/src/main/rascal/lang/jimple/core/Context.rsc +++ b/src/main/rascal/lang/jimple/core/Context.rsc @@ -95,7 +95,7 @@ ExecutionContext createExecutionContext(list[loc] classPath, list[str] entryPoin return ExecutionContext(ct, mt); } -private CID jimplify(CID c) = jimplify([processJimpleLabels, processConstantPropagator], c); +private CID jimplify(CID c) = jimplify([processJimpleLabels], c); private CID jimplify(list[CID (CID)] fs, CID c) { switch(fs) { diff --git a/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc b/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc index d56e154f..eae02a2e 100644 --- a/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc +++ b/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc @@ -24,7 +24,8 @@ public PrettyPrintMap PrettyPrint(ExecutionContext ctx) { PrettyPrintMap ppMap = (); top-down visit(ctx) { - case classDecl(n, ms, s, is, fs, mss): ppMap[prettyPrint(n)] = prettyPrint(classDecl(n, ms, s, is, fs, mss)); + case classDecl(n, ms, s, is, fs, mss): ppMap[prettyPrint(n)] = prettyPrint(classDecl(n, ms, s, is, fs, mss)); + case interfaceDecl(n, ms, is, fs, mss):ppMap[prettyPrint(n)] = prettyPrint(interfaceDecl(n, ms, is, fs, mss)); } return ppMap; } diff --git a/src/test/java/lang/jimple/internal/TestDecompiler.java b/src/test/java/lang/jimple/internal/TestDecompiler.java index 5aabe2c0..7d8cb211 100644 --- a/src/test/java/lang/jimple/internal/TestDecompiler.java +++ b/src/test/java/lang/jimple/internal/TestDecompiler.java @@ -124,6 +124,7 @@ public void decompileWhileStmtSampleClass() { } } + @Ignore @Test public void decompileSlf4JMDCClass() { try { diff --git a/src/test/java/samples/arrays/ArrayExample.java b/src/test/java/samples/arrays/ArrayExample.java new file mode 100644 index 00000000..e4be2189 --- /dev/null +++ b/src/test/java/samples/arrays/ArrayExample.java @@ -0,0 +1,28 @@ +package samples.arrays; + +import java.util.Arrays; +import java.util.List; + +public class ArrayExample { + + public static void main(String[] args) throws Exception { + List nums = Arrays.asList(-3, 0, 1, 8); + + Runnable r = () -> nums.forEach(n -> { + + if (n < 0) System.out.println("Negative: " + n); + + else System.out.println("Positive: " + n); + + }); + + Thread t = new Thread(r); + + t.start(); + + t.join(); + + } + +} + diff --git a/src/test/resources/sootOutput/org.slf4j.MDC.jimple b/src/test/resources/sootOutput/org.slf4j.MDC.jimple deleted file mode 100644 index 8af6fe3d..00000000 --- a/src/test/resources/sootOutput/org.slf4j.MDC.jimple +++ /dev/null @@ -1,279 +0,0 @@ -public class org.slf4j.MDC extends java.lang.Object -{ - static final java.lang.String NULL_MDCA_URL; - static final java.lang.String NO_STATIC_MDC_BINDER_URL; - static org.slf4j.spi.MDCAdapter mdcAdapter; - - private void () - { - org.slf4j.MDC r0; - - r0 := @this: org.slf4j.MDC; - - specialinvoke r0.()>(); - - return; - } - - public static void put(java.lang.String, java.lang.String) throws java.lang.IllegalArgumentException - { - java.lang.String r0, r2; - org.slf4j.spi.MDCAdapter $r1, $r3; - java.lang.IllegalStateException $r4; - java.lang.IllegalArgumentException $r5; - - r0 := @parameter0: java.lang.String; - - r2 := @parameter1: java.lang.String; - - if r0 != null goto label1; - - $r5 = new java.lang.IllegalArgumentException; - - specialinvoke $r5.(java.lang.String)>("key parameter cannot be null"); - - throw $r5; - - label1: - $r1 = ; - - if $r1 != null goto label2; - - $r4 = new java.lang.IllegalStateException; - - specialinvoke $r4.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); - - throw $r4; - - label2: - $r3 = ; - - interfaceinvoke $r3.(r0, r2); - - return; - } - - public static java.lang.String get(java.lang.String) throws java.lang.IllegalArgumentException - { - java.lang.String r0, $r3; - org.slf4j.spi.MDCAdapter $r1, $r2; - java.lang.IllegalStateException $r4; - java.lang.IllegalArgumentException $r5; - - r0 := @parameter0: java.lang.String; - - if r0 != null goto label1; - - $r5 = new java.lang.IllegalArgumentException; - - specialinvoke $r5.(java.lang.String)>("key parameter cannot be null"); - - throw $r5; - - label1: - $r1 = ; - - if $r1 != null goto label2; - - $r4 = new java.lang.IllegalStateException; - - specialinvoke $r4.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); - - throw $r4; - - label2: - $r2 = ; - - $r3 = interfaceinvoke $r2.(r0); - - return $r3; - } - - public static void remove(java.lang.String) throws java.lang.IllegalArgumentException - { - java.lang.String r0; - org.slf4j.spi.MDCAdapter $r1, $r2; - java.lang.IllegalStateException $r3; - java.lang.IllegalArgumentException $r4; - - r0 := @parameter0: java.lang.String; - - if r0 != null goto label1; - - $r4 = new java.lang.IllegalArgumentException; - - specialinvoke $r4.(java.lang.String)>("key parameter cannot be null"); - - throw $r4; - - label1: - $r1 = ; - - if $r1 != null goto label2; - - $r3 = new java.lang.IllegalStateException; - - specialinvoke $r3.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); - - throw $r3; - - label2: - $r2 = ; - - interfaceinvoke $r2.(r0); - - return; - } - - public static void clear() - { - org.slf4j.spi.MDCAdapter $r0, $r1; - java.lang.IllegalStateException $r2; - - $r0 = ; - - if $r0 != null goto label1; - - $r2 = new java.lang.IllegalStateException; - - specialinvoke $r2.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); - - throw $r2; - - label1: - $r1 = ; - - interfaceinvoke $r1.(); - - return; - } - - public static java.util.Map getCopyOfContextMap() - { - org.slf4j.spi.MDCAdapter $r0, $r1; - java.util.Map $r2; - java.lang.IllegalStateException $r3; - - $r0 = ; - - if $r0 != null goto label1; - - $r3 = new java.lang.IllegalStateException; - - specialinvoke $r3.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); - - throw $r3; - - label1: - $r1 = ; - - $r2 = interfaceinvoke $r1.(); - - return $r2; - } - - public static void setContextMap(java.util.Map) - { - org.slf4j.spi.MDCAdapter $r0, $r2; - java.util.Map r1; - java.lang.IllegalStateException $r3; - - r1 := @parameter0: java.util.Map; - - $r0 = ; - - if $r0 != null goto label1; - - $r3 = new java.lang.IllegalStateException; - - specialinvoke $r3.(java.lang.String)>("MDCAdapter cannot be null. See also http://www.slf4j.org/codes.html#null_MDCA"); - - throw $r3; - - label1: - $r2 = ; - - interfaceinvoke $r2.(r1); - - return; - } - - public static org.slf4j.spi.MDCAdapter getMDCAdapter() - { - org.slf4j.spi.MDCAdapter $r0; - - $r0 = ; - - return $r0; - } - - static void () - { - org.slf4j.impl.StaticMDCBinder $r0, $r5; - org.slf4j.spi.MDCAdapter $r1; - java.lang.Exception $r2; - java.lang.StringBuffer $r3, $r4, $r7, $r8; - java.lang.String $r6, $r9, r11; - java.lang.NoClassDefFoundError $r10; - int $i0; - - = "http://www.slf4j.org/codes.html#no_static_mdc_binder"; - - = "http://www.slf4j.org/codes.html#null_MDCA"; - - label1: - $r0 = ; - - $r1 = virtualinvoke $r0.(); - - = $r1; - - label2: - goto label6; - - label3: - $r10 := @caughtexception; - - r11 = virtualinvoke $r10.(); - - if r11 == null goto label4; - - $i0 = virtualinvoke r11.("org/slf4j/impl/StaticMDCBinder"); - - if $i0 == -1 goto label4; - - staticinvoke ("Failed to load class \"org.slf4j.impl.StaticMDCBinder\"."); - - staticinvoke ("See http://www.slf4j.org/codes.html#no_static_mdc_binder for further details."); - - label4: - throw $r10; - - label5: - $r2 := @caughtexception; - - $r3 = new java.lang.StringBuffer; - - specialinvoke $r3.()>(); - - $r4 = virtualinvoke $r3.("Could not bind with an instance of class ["); - - $r5 = ; - - $r6 = virtualinvoke $r5.(); - - $r7 = virtualinvoke $r4.($r6); - - $r8 = virtualinvoke $r7.("]"); - - $r9 = virtualinvoke $r8.(); - - staticinvoke ($r9, $r2); - - label6: - return; - - catch java.lang.NoClassDefFoundError from label1 to label2 with label3; - catch java.lang.Exception from label1 to label2 with label5; - } -} diff --git a/src/test/resources/sootOutput/org/slf4j/MDC.class b/src/test/resources/sootOutput/org/slf4j/MDC.class deleted file mode 100644 index cbf117a5849233ffc8858754919df4b7b0412de5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2509 zcmbVNTXz#x7~Ll=&7D^ZyHuJUtU|6H9w94fdr3p>V!6>u2z<&mgWoUU3GfCG&8%n zN#x%H#}puiQ6@^ZMFS7 z0t4fj`vT`8NF}>q8lE>J8*_Hos?WNv?Z$CT;COUrcC#iOzinG_9H(&}xBwSES-G@QceBu?UtK)fk^mAk;%@l225K1>?k#Mu;0 z-qJ9Hqe;YYo{T7C>3K#|3XIS`f)G|t!`m23A&mG%a+o$jw<*QL*p9uvII z1o!hd-EA}^<#9vc@a;fR8a~8u3X}LqAX~7zW?i>zUsp2KH`;znH!QtvQNUJB>UJaK zXEg!J^047J(y9ww?nm=$%y z(=qITg{T|#nqdV5NnMSIoUW>7n4W!b>7t49g<_p`FJqCjB~sC=O%lhFh6M~C!7|wM z1LR8JVjs+X`b1#tHDFV2v)hrD--GQNw&_FpSa%H9=tvHteee?aHicCzYWNx}Dvv7X z3iBw~&f{{UU|YW2^cM_A;Mi`rcG&@WzG9sXtSOrsyWy2O6N}R&mP>uG^wckGc~!gy zn#xm)nsa5xek3)l{^3Z{$uG_pG5VLz2#}9l(b0u;AzF~IR ztb+x92q-#Aq4qF!WcQGWnPxb6IB-Ehe zS(2+aFwC1icR%uOjL-5@jBerFuh4(S?7i$3-YHJ}fm0LdcegMR`w2toE6;E({Q>{7 zFYmp;M4u&wvV|)s}JCxl<@kwx;RLTsGuMxfaop}oVPYk_4c_sbjHYzW< ze~zyNl*vx?1fRpf<)o4nqbL$ebfEl?X9M%qmGpyce5cI!yURYu_c8pk=Wm1_jw&n) z!MWYVBW?!iah1p^LatPle@~NREOOhMro`FMfx@ePgG@}_Rm4)6A&6yyP?gLa3}WIr z+5 Date: Mon, 22 Feb 2021 18:00:24 -0300 Subject: [PATCH 14/16] remove constant propagator until FlowGraph is fixed, fix pp for interfaces and ignore a failing test --- src/main/rascal/lang/jimple/core/Context.rsc | 2 +- src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc | 3 ++- src/test/java/lang/jimple/internal/TestDecompiler.java | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/rascal/lang/jimple/core/Context.rsc b/src/main/rascal/lang/jimple/core/Context.rsc index 751dff83..3e506b9c 100644 --- a/src/main/rascal/lang/jimple/core/Context.rsc +++ b/src/main/rascal/lang/jimple/core/Context.rsc @@ -95,7 +95,7 @@ ExecutionContext createExecutionContext(list[loc] classPath, list[str] entryPoin return ExecutionContext(ct, mt); } -private CID jimplify(CID c) = jimplify([processJimpleLabels, processConstantPropagator], c); +private CID jimplify(CID c) = jimplify([processJimpleLabels], c); private CID jimplify(list[CID (CID)] fs, CID c) { switch(fs) { diff --git a/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc b/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc index d56e154f..eae02a2e 100644 --- a/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc +++ b/src/main/rascal/lang/jimple/toolkit/PrettyPrinter.rsc @@ -24,7 +24,8 @@ public PrettyPrintMap PrettyPrint(ExecutionContext ctx) { PrettyPrintMap ppMap = (); top-down visit(ctx) { - case classDecl(n, ms, s, is, fs, mss): ppMap[prettyPrint(n)] = prettyPrint(classDecl(n, ms, s, is, fs, mss)); + case classDecl(n, ms, s, is, fs, mss): ppMap[prettyPrint(n)] = prettyPrint(classDecl(n, ms, s, is, fs, mss)); + case interfaceDecl(n, ms, is, fs, mss):ppMap[prettyPrint(n)] = prettyPrint(interfaceDecl(n, ms, is, fs, mss)); } return ppMap; } diff --git a/src/test/java/lang/jimple/internal/TestDecompiler.java b/src/test/java/lang/jimple/internal/TestDecompiler.java index 5aabe2c0..7d8cb211 100644 --- a/src/test/java/lang/jimple/internal/TestDecompiler.java +++ b/src/test/java/lang/jimple/internal/TestDecompiler.java @@ -124,6 +124,7 @@ public void decompileWhileStmtSampleClass() { } } + @Ignore @Test public void decompileSlf4JMDCClass() { try { From b780c7f3c692715bfd8296cd6f2086ced579c8ce Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Mon, 22 Feb 2021 18:02:02 -0300 Subject: [PATCH 15/16] adds a array test case --- .../java/samples/arrays/ArrayExample.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/java/samples/arrays/ArrayExample.java diff --git a/src/test/java/samples/arrays/ArrayExample.java b/src/test/java/samples/arrays/ArrayExample.java new file mode 100644 index 00000000..e4be2189 --- /dev/null +++ b/src/test/java/samples/arrays/ArrayExample.java @@ -0,0 +1,28 @@ +package samples.arrays; + +import java.util.Arrays; +import java.util.List; + +public class ArrayExample { + + public static void main(String[] args) throws Exception { + List nums = Arrays.asList(-3, 0, 1, 8); + + Runnable r = () -> nums.forEach(n -> { + + if (n < 0) System.out.println("Negative: " + n); + + else System.out.println("Positive: " + n); + + }); + + Thread t = new Thread(r); + + t.start(); + + t.join(); + + } + +} + From 42fa0fa41f4190c7c7192f9727cb0a48b751c0cb Mon Sep 17 00:00:00 2001 From: Fausto Carvalho Date: Sat, 27 Feb 2021 11:53:06 -0300 Subject: [PATCH 16/16] adding a rascal maven plugin for building rascal modules --- META-INF/RASCAL.MF | 1 + pom.xml | 30 +++++++++++++++++++ .../lang/jimple/util/JPrettyPrinter.rsc | 6 ++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/META-INF/RASCAL.MF b/META-INF/RASCAL.MF index 56e9b3b1..f8cfc2dc 100644 --- a/META-INF/RASCAL.MF +++ b/META-INF/RASCAL.MF @@ -4,3 +4,4 @@ Project-Name: JimpleFramework Courses: courses Main-Module: Plugin Source: src/main/rascal,src/test/rascal +Require-Libraries: |lib://rascal_eclipse| \ No newline at end of file diff --git a/pom.xml b/pom.xml index 63972cf2..2fa0cb42 100644 --- a/pom.xml +++ b/pom.xml @@ -27,12 +27,14 @@ rascal 0.18.0 + junit junit 4.13.1 test + org.projectlombok lombok @@ -53,6 +55,34 @@ 1.8 + + + org.rascalmpl + rascal-maven-plugin + 0.3.4 + + ${project.build.outputDirectory} + true + true + + ${project.basedir}/src/main/rascal + + + ${project.basedir}/src/main/rascal/lang/jimple/toolkit/GraphUtil.rsc + ${project.basedir}/src/main/rascal/lang/jimple/toolkit/CallGraph.rsc + + + + + it-compile + compile + + compile + + + + + diff --git a/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc b/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc index 9bb56dfb..2b1dfa9b 100644 --- a/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc +++ b/src/main/rascal/lang/jimple/util/JPrettyPrinter.rsc @@ -240,7 +240,7 @@ public str prettyPrint(list[Type] types, str n) { return text; } -public str prettyPrint(Field f: field(modifiers, fieldType, name)) = +public str prettyPrint(Field::field(modifiers, fieldType, name)) = " ;"; public str prettyPrint(list[Field] fields) = @@ -251,7 +251,7 @@ public str prettyPrint(list[Field] fields) = public str prettyPrint(LocalVariableDeclaration::localVariableDeclaration(Type varType, Identifier local)) = " ;"; -public str prettyPrint(MethodBody body: methodBody(localVars, stmts, catchClauses)) = +public str prettyPrint(MethodBody::methodBody(localVars, stmts, catchClauses)) = " ' <}> ' @@ -259,7 +259,7 @@ public str prettyPrint(MethodBody body: methodBody(localVars, stmts, catchClause '<} else {> ' <}><}> \n <}>"; -public str prettyPrint(Method m: method(modifiers, returnType, name, formals, exceptions, body)) = +public str prettyPrint(Method::method(modifiers, returnType, name, formals, exceptions, body)) = " () '{ '}