- method attribute 'default' (Java 8)

- instruction 'invokedynamic' (Java 7)
- bugfixing
master
Stiver 11 years ago
parent c9c426ded7
commit 96379678e6
  1. 11
      src/de/fernflower/code/CodeConstants.java
  2. 19
      src/de/fernflower/code/ConstantsUtil.java
  3. 3
      src/de/fernflower/code/Instruction.java
  4. 21
      src/de/fernflower/code/interpreter/InstructionImpact.java
  5. 20
      src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java
  6. 15
      src/de/fernflower/main/ClassReference14Processor.java
  7. 5
      src/de/fernflower/main/ClassWriter.java
  8. 6
      src/de/fernflower/main/rels/MethodProcessorThread.java
  9. 13
      src/de/fernflower/modules/decompiler/ExprProcessor.java
  10. 57
      src/de/fernflower/modules/decompiler/FinallyProcessor.java
  11. 22
      src/de/fernflower/modules/decompiler/exps/InvocationExprent.java
  12. 15
      src/de/fernflower/modules/decompiler/sforms/FlattenStatementsHelper.java
  13. 184
      src/de/fernflower/modules/decompiler/sforms/SSAConstructorSparseEx.java
  14. 83
      src/de/fernflower/modules/decompiler/sforms/SSAUConstructorSparseEx.java
  15. 23
      src/de/fernflower/struct/StructClass.java
  16. 15
      src/de/fernflower/struct/StructMethod.java

@ -16,6 +16,16 @@ package de.fernflower.code;
public interface CodeConstants { public interface CodeConstants {
// ----------------------------------------------------------------------
// BYTECODE VERSIONS
// ----------------------------------------------------------------------
public final static int BYTECODE_JAVA_LE_4 = 1;
public final static int BYTECODE_JAVA_5 = 2;
public final static int BYTECODE_JAVA_6 = 3;
public final static int BYTECODE_JAVA_7 = 4;
public final static int BYTECODE_JAVA_8 = 5;
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// VARIABLE TYPES // VARIABLE TYPES
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -339,6 +349,7 @@ public interface CodeConstants {
public final static int opc_invokespecial = 183; public final static int opc_invokespecial = 183;
public final static int opc_invokestatic = 184; public final static int opc_invokestatic = 184;
public final static int opc_invokeinterface = 185; public final static int opc_invokeinterface = 185;
public final static int opc_invokedynamic = 186;
public final static int opc_xxxunusedxxx = 186; public final static int opc_xxxunusedxxx = 186;
public final static int opc_new = 187; public final static int opc_new = 187;
public final static int opc_newarray = 188; public final static int opc_newarray = 188;

@ -30,6 +30,7 @@ import de.fernflower.code.optinstructions.GOTO_W;
import de.fernflower.code.optinstructions.IINC; import de.fernflower.code.optinstructions.IINC;
import de.fernflower.code.optinstructions.ILOAD; import de.fernflower.code.optinstructions.ILOAD;
import de.fernflower.code.optinstructions.INSTANCEOF; import de.fernflower.code.optinstructions.INSTANCEOF;
import de.fernflower.code.optinstructions.INVOKEDYNAMIC;
import de.fernflower.code.optinstructions.INVOKEINTERFACE; import de.fernflower.code.optinstructions.INVOKEINTERFACE;
import de.fernflower.code.optinstructions.INVOKESPECIAL; import de.fernflower.code.optinstructions.INVOKESPECIAL;
import de.fernflower.code.optinstructions.INVOKESTATIC; import de.fernflower.code.optinstructions.INVOKESTATIC;
@ -58,17 +59,18 @@ public class ConstantsUtil {
return opcodeNames[opcode]; return opcodeNames[opcode];
} }
public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int[] operands) { public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int bytecode_version, int[] operands) {
Instruction instr = getInstructionInstance(opcode); Instruction instr = getInstructionInstance(opcode, bytecode_version);
instr.wide = wide; instr.wide = wide;
instr.group = group; instr.group = group;
instr.bytecode_version = bytecode_version;
instr.setOperands(operands); instr.setOperands(operands);
return instr; return instr;
} }
public static Instruction getInstructionInstance(int opcode) { private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
try { try {
Instruction instr; Instruction instr;
@ -78,7 +80,13 @@ public class ConstantsUtil {
opcode == CodeConstants.opc_ifnonnull) { opcode == CodeConstants.opc_ifnonnull) {
instr = new IfInstruction(); instr = new IfInstruction();
} else { } else {
Class cl = opcodeClasses[opcode]; Class cl = opcodeClasses[opcode];
if(opcode == CodeConstants.opc_invokedynamic && bytecode_version < CodeConstants.BYTECODE_JAVA_7) {
cl = null; // instruction unused in Java 6 and before
}
if(cl == null) { if(cl == null) {
instr = new Instruction(); instr = new Instruction();
} else { } else {
@ -282,7 +290,8 @@ public class ConstantsUtil {
"invokespecial", // "invokespecial", "invokespecial", // "invokespecial",
"invokestatic", // "invokestatic", "invokestatic", // "invokestatic",
"invokeinterface", // "invokeinterface", "invokeinterface", // "invokeinterface",
"xxxunusedxxx", // "xxxunusedxxx", //"xxxunusedxxx", // "xxxunusedxxx", Java 6 and before
"invokedynamic", // "invokedynamic", Java 7 and later
"new", // "new", "new", // "new",
"newarray", // "newarray", "newarray", // "newarray",
"anewarray", // "anewarray", "anewarray", // "anewarray",
@ -487,7 +496,7 @@ public class ConstantsUtil {
INVOKESPECIAL.class, // "invokespecial", INVOKESPECIAL.class, // "invokespecial",
INVOKESTATIC.class, // "invokestatic", INVOKESTATIC.class, // "invokestatic",
INVOKEINTERFACE.class, // "invokeinterface", INVOKEINTERFACE.class, // "invokeinterface",
null , // "xxxunusedxxx", INVOKEDYNAMIC.class, // "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
NEW.class, // "new", NEW.class, // "new",
NEWARRAY.class, // "newarray", NEWARRAY.class, // "newarray",
ANEWARRAY.class, // "anewarray", ANEWARRAY.class, // "anewarray",

@ -29,6 +29,7 @@ public class Instruction implements CodeConstants {
public boolean wide = false; public boolean wide = false;
public int bytecode_version = BYTECODE_JAVA_LE_4;
// ***************************************************************************** // *****************************************************************************
// private fields // private fields
@ -55,7 +56,7 @@ public class Instruction implements CodeConstants {
} }
public Instruction clone() { public Instruction clone() {
return ConstantsUtil.getInstructionInstance(opcode, wide, group, operands==null?null:(int[])operands.clone()); return ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, operands==null?null:(int[])operands.clone());
} }
public String toString() { public String toString() {

@ -413,15 +413,18 @@ public class InstructionImpact {
case CodeConstants.opc_invokeinterface: case CodeConstants.opc_invokeinterface:
stack.pop(); stack.pop();
case CodeConstants.opc_invokestatic: case CodeConstants.opc_invokestatic:
ck = pool.getLinkConstant(instr.getOperand(0)); case CodeConstants.opc_invokedynamic:
MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor); if(instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
for(int i=0;i<md.params.length;i++) { ck = pool.getLinkConstant(instr.getOperand(0));
stack.pop(md.params[i].stack_size); MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
} for(int i=0;i<md.params.length;i++) {
if(md.ret.type != CodeConstants.TYPE_VOID) { stack.pop(md.params[i].stack_size);
stack.push(md.ret); }
if(md.ret.stack_size==2) { if(md.ret.type != CodeConstants.TYPE_VOID) {
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY)); stack.push(md.ret);
if(md.ret.stack_size==2) {
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
}
} }
} }
break; break;

@ -0,0 +1,20 @@
package de.fernflower.code.optinstructions;
import java.io.DataOutputStream;
import java.io.IOException;
import de.fernflower.code.Instruction;
public class INVOKEDYNAMIC extends Instruction {
public void writeToStream(DataOutputStream out, int offset) throws IOException {
out.writeByte(opc_invokedynamic);
out.writeShort(getOperand(0));
out.writeByte(0);
out.writeByte(0);
}
public int length() {
return 5;
}
}

@ -95,16 +95,19 @@ public class ClassReference14Processor {
ClassWrapper wrapper = node.wrapper; ClassWrapper wrapper = node.wrapper;
int major_version = wrapper.getClassStruct().major_version; // int major_version = wrapper.getClassStruct().major_version;
int minor_version = wrapper.getClassStruct().minor_version; // int minor_version = wrapper.getClassStruct().minor_version;
//
if(major_version > 48 || (major_version == 48 && minor_version > 0)) { // if(major_version > 48 || (major_version == 48 && minor_version > 0)) {
// // version 1.5 or above
// return;
// }
if(wrapper.getClassStruct().isVersionGE_1_5()) {
// version 1.5 or above // version 1.5 or above
return; return;
} }
// find the synthetic method Class class$(String) if present // find the synthetic method Class class$(String) if present
HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>(); HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
findClassMethod(node, mapClassMeths); findClassMethod(node, mapClassMeths);

@ -587,6 +587,11 @@ public class ClassWriter {
} }
} }
// 'default' modifier (Java 8)
if(isInterface && mt.containsCode()) {
bufstrwriter.write("default ");
}
GenericMethodDescriptor descriptor = null; GenericMethodDescriptor descriptor = null;
if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature"); StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");

@ -102,7 +102,7 @@ public class MethodProcessorThread implements Runnable {
// System.out.println(); // System.out.println();
// } // }
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true); //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true);
DeadCodeHelper.removeDeadBlocks(graph); DeadCodeHelper.removeDeadBlocks(graph);
graph.inlineJsr(mt); graph.inlineJsr(mt);
@ -142,7 +142,7 @@ public class MethodProcessorThread implements Runnable {
DecompilerContext.getCountercontainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables()); DecompilerContext.getCountercontainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true); //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
System.out.println(graph.toString()); //System.out.println(graph.toString());
if(ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) { if(ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.WARNING); DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.WARNING);
@ -157,7 +157,7 @@ public class MethodProcessorThread implements Runnable {
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true); //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true);
//System.out.println(graph.toString()); //System.out.println(graph.toString());
System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava()); //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
root = DomHelper.parseGraph(graph); root = DomHelper.parseGraph(graph);
} }

@ -527,11 +527,14 @@ public class ExprProcessor implements CodeConstants {
case opc_invokespecial: case opc_invokespecial:
case opc_invokestatic: case opc_invokestatic:
case opc_invokeinterface: case opc_invokeinterface:
InvocationExprent exprinv = new InvocationExprent(instr.opcode, pool.getLinkConstant(instr.getOperand(0)), stack); case opc_invokedynamic:
if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) { if(instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
exprlist.add(exprinv); InvocationExprent exprinv = new InvocationExprent(instr.opcode, pool.getLinkConstant(instr.getOperand(0)), stack);
} else { if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
pushEx(stack, exprlist, exprinv); exprlist.add(exprinv);
} else {
pushEx(stack, exprlist, exprinv);
}
} }
break; break;
case opc_new: case opc_new:

@ -14,16 +14,13 @@
package de.fernflower.modules.decompiler; package de.fernflower.modules.decompiler;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import test.util.DotExporter;
import de.fernflower.code.CodeConstants; import de.fernflower.code.CodeConstants;
import de.fernflower.code.ConstantsUtil; import de.fernflower.code.ConstantsUtil;
import de.fernflower.code.Instruction; import de.fernflower.code.Instruction;
@ -73,6 +70,8 @@ public class FinallyProcessor {
private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) { private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
int bytecode_version = mt.getClassStruct().getBytecodeVersion();
LinkedList<Statement> stack = new LinkedList<Statement>(); LinkedList<Statement> stack = new LinkedList<Statement>();
stack.add(root); stack.add(root);
@ -110,7 +109,7 @@ public class FinallyProcessor {
} else { } else {
int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER); int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf); insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
finallyBlockIDs.put(handler.id, varindex); finallyBlockIDs.put(handler.id, varindex);
} }
@ -360,7 +359,7 @@ public class FinallyProcessor {
return new Object[] {firstcode, mapLast}; return new Object[] {firstcode, mapLast};
} }
private void insertSemaphore(ControlFlowGraph graph, HashSet<BasicBlock> setTry, BasicBlock head, BasicBlock handler, int var, Object[] information) { private void insertSemaphore(ControlFlowGraph graph, HashSet<BasicBlock> setTry, BasicBlock head, BasicBlock handler, int var, Object[] information, int bytecode_version) {
HashSet<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry); HashSet<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry);
@ -389,8 +388,8 @@ public class FinallyProcessor {
// disable semaphore // disable semaphore
SimpleInstructionSequence seq = new SimpleInstructionSequence(); SimpleInstructionSequence seq = new SimpleInstructionSequence();
seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, new int[]{0}) , -1); seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}) , -1);
seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, new int[]{var}) , -1); seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}) , -1);
// build a separate block // build a separate block
BasicBlock newblock = new BasicBlock(++graph.last_id); BasicBlock newblock = new BasicBlock(++graph.last_id);
@ -419,8 +418,8 @@ public class FinallyProcessor {
// enable semaphor at the statement entrance // enable semaphor at the statement entrance
SimpleInstructionSequence seq = new SimpleInstructionSequence(); SimpleInstructionSequence seq = new SimpleInstructionSequence();
seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, new int[]{1}) , -1); seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}) , -1);
seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, new int[]{var}) , -1); seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}) , -1);
BasicBlock newhead = new BasicBlock(++graph.last_id); BasicBlock newhead = new BasicBlock(++graph.last_id);
newhead.setSeq(seq); newhead.setSeq(seq);
@ -429,8 +428,8 @@ public class FinallyProcessor {
// initialize semaphor with false // initialize semaphor with false
seq = new SimpleInstructionSequence(); seq = new SimpleInstructionSequence();
seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, new int[]{0}) , -1); seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}) , -1);
seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, new int[]{var}) , -1); seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}) , -1);
BasicBlock newheadinit = new BasicBlock(++graph.last_id); BasicBlock newheadinit = new BasicBlock(++graph.last_id);
newheadinit.setSeq(seq); newheadinit.setSeq(seq);
@ -566,9 +565,9 @@ public class FinallyProcessor {
lstAreas.add(new Object[] {start, arr[0], arr[1]}); lstAreas.add(new Object[] {start, arr[0], arr[1]});
} }
try { // try {
DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true); // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
} catch(Exception ex){ex.printStackTrace();} // } catch(Exception ex){ex.printStackTrace();}
// delete areas // delete areas
for(Object[] area: lstAreas) { for(Object[] area: lstAreas) {
@ -941,25 +940,25 @@ public class FinallyProcessor {
// remove all the blocks inbetween // remove all the blocks inbetween
for(BasicBlock block: setBlocks) { for(BasicBlock block: setBlocks) {
if(!block.getSuccExceptions().containsAll(setCommonExceptionHandlers)) {
is_outside_range = true;
}
HashSet<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
for(BasicBlock handler : block.getSuccExceptions()) {
setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
}
if(setCommonRemovedExceptionRanges == null) {
setCommonRemovedExceptionRanges = setRemovedExceptionRanges;
} else {
setCommonRemovedExceptionRanges.retainAll(setRemovedExceptionRanges);
}
// artificial basic blocks (those resulted from splitting) // artificial basic blocks (those resulted from splitting)
// can belong to more than one area // can belong to more than one area
if(graph.getBlocks().containsKey(block.id)) { if(graph.getBlocks().containsKey(block.id)) {
if(!block.getSuccExceptions().containsAll(setCommonExceptionHandlers)) {
is_outside_range = true;
}
HashSet<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
for(BasicBlock handler : block.getSuccExceptions()) {
setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
}
if(setCommonRemovedExceptionRanges == null) {
setCommonRemovedExceptionRanges = setRemovedExceptionRanges;
} else {
setCommonRemovedExceptionRanges.retainAll(setRemovedExceptionRanges);
}
// shift extern edges on splitted blocks // shift extern edges on splitted blocks
if(block.getSeq().isEmpty() && block.getSuccs().size() == 1) { if(block.getSeq().isEmpty() && block.getSuccs().size() == 1) {
BasicBlock succs = block.getSuccs().get(0); BasicBlock succs = block.getSuccs().get(0);

@ -43,6 +43,7 @@ public class InvocationExprent extends Exprent {
public static final int INVOKE_VIRTUAL = 2; public static final int INVOKE_VIRTUAL = 2;
public static final int INVOKE_STATIC = 3; public static final int INVOKE_STATIC = 3;
public static final int INVOKE_INTERFACE = 4; public static final int INVOKE_INTERFACE = 4;
public static final int INVOKE_DYNAMIC = 5;
public static final int TYP_GENERAL = 1; public static final int TYP_GENERAL = 1;
public static final int TYP_INIT = 2; public static final int TYP_INIT = 2;
@ -93,6 +94,10 @@ public class InvocationExprent extends Exprent {
break; break;
case CodeConstants.opc_invokeinterface: case CodeConstants.opc_invokeinterface:
invocationTyp = INVOKE_INTERFACE; invocationTyp = INVOKE_INTERFACE;
break;
case CodeConstants.opc_invokedynamic:
invocationTyp = INVOKE_DYNAMIC;
classname = "java/lang/Class"; // dummy class name
} }
if("<init>".equals(name)) { if("<init>".equals(name)) {
@ -108,7 +113,7 @@ public class InvocationExprent extends Exprent {
lstParameters.add(0, stack.pop()); lstParameters.add(0, stack.pop());
} }
if(opcode == CodeConstants.opc_invokestatic) { if(opcode == CodeConstants.opc_invokestatic || opcode == CodeConstants.opc_invokedynamic) {
isStatic = true; isStatic = true;
} else { } else {
instance = stack.pop(); instance = stack.pop();
@ -174,9 +179,11 @@ public class InvocationExprent extends Exprent {
boolean isInstanceThis = false; boolean isInstanceThis = false;
if(isStatic) { if(isStatic) {
ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE); if(invocationTyp != INVOKE_DYNAMIC) {
if(node == null || !classname.equals(node.classStruct.qualifiedName)) { ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname))); if(node == null || !classname.equals(node.classStruct.qualifiedName)) {
buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
}
} }
} else { } else {
@ -249,7 +256,12 @@ public class InvocationExprent extends Exprent {
buf.append("."); buf.append(".");
} }
buf.append(name+"("); buf.append(name);
if(invocationTyp == INVOKE_DYNAMIC) {
buf.append("<invokedynamic>");
}
buf.append("(");
break; break;
case TYP_CLINIT: case TYP_CLINIT:
throw new RuntimeException("Explicite invocation of <clinit>"); throw new RuntimeException("Explicite invocation of <clinit>");

@ -408,17 +408,19 @@ public class FlattenStatementsHelper {
if(finallyShortRangeSource != null) { if(finallyShortRangeSource != null) {
boolean isContinueEdge = (edgetype == StatEdge.TYPE_CONTINUE);
List<String[]> lst = mapShortRangeFinallyPathIds.get(sourcenode.id); List<String[]> lst = mapShortRangeFinallyPathIds.get(sourcenode.id);
if(lst == null) { if(lst == null) {
mapShortRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>()); mapShortRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
} }
lst.add(new String[]{finallyShortRangeSource.id, destination.id.toString(), finallyShortRangeEntry.id.toString(), isFinallyMonitorExceptionPath?"1":null}); lst.add(new String[]{finallyShortRangeSource.id, destination.id.toString(), finallyShortRangeEntry.id.toString(), isFinallyMonitorExceptionPath?"1":null, isContinueEdge?"1":null});
lst = mapLongRangeFinallyPathIds.get(sourcenode.id); lst = mapLongRangeFinallyPathIds.get(sourcenode.id);
if(lst == null) { if(lst == null) {
mapLongRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>()); mapLongRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
} }
lst.add(new String[]{finallyLongRangeSource.id, destination.id.toString(), finallyLongRangeEntry.id.toString()}); lst.add(new String[]{finallyLongRangeSource.id, destination.id.toString(), finallyLongRangeEntry.id.toString(), isContinueEdge?"1":null});
} }
} }
@ -454,7 +456,10 @@ public class FlattenStatementsHelper {
List<String[]> lst = ent.getValue(); List<String[]> lst = ent.getValue();
for(String[] arr : lst) { for(String[] arr : lst) {
DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[1]))[0]);
boolean isContinueEdge = arr[i==0?4:3] != null;
DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[1]))[isContinueEdge?1:0]);
DirectNode enter = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[2]))[0]); DirectNode enter = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[2]))[0]);
newLst.add(new FinallyPathWrapper(arr[0], dest.id, enter.id)); newLst.add(new FinallyPathWrapper(arr[0], dest.id, enter.id));
@ -505,6 +510,10 @@ public class FlattenStatementsHelper {
public int hashCode() { public int hashCode() {
return (source+":"+destination+":"+entry).hashCode(); return (source+":"+destination+":"+entry).hashCode();
} }
public String toString() {
return source + "->(" + entry + ")->" + destination;
}
} }

@ -14,12 +14,14 @@
package de.fernflower.modules.decompiler.sforms; package de.fernflower.modules.decompiler.sforms;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import test.util.DotExporter;
import de.fernflower.code.CodeConstants; import de.fernflower.code.CodeConstants;
import de.fernflower.modules.decompiler.exps.AssignmentExprent; import de.fernflower.modules.decompiler.exps.AssignmentExprent;
import de.fernflower.modules.decompiler.exps.Exprent; import de.fernflower.modules.decompiler.exps.Exprent;
@ -34,9 +36,9 @@ import de.fernflower.modules.decompiler.vars.VarVersionPaar;
import de.fernflower.struct.StructMethod; import de.fernflower.struct.StructMethod;
import de.fernflower.struct.gen.MethodDescriptor; import de.fernflower.struct.gen.MethodDescriptor;
import de.fernflower.util.FastSparseSetFactory; import de.fernflower.util.FastSparseSetFactory;
import de.fernflower.util.FastSparseSetFactory.FastSparseSet;
import de.fernflower.util.InterpreterUtil; import de.fernflower.util.InterpreterUtil;
import de.fernflower.util.SFormsFastMapDirect; import de.fernflower.util.SFormsFastMapDirect;
import de.fernflower.util.FastSparseSetFactory.FastSparseSet;
public class SSAConstructorSparseEx { public class SSAConstructorSparseEx {
@ -68,12 +70,12 @@ public class SSAConstructorSparseEx {
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
DirectGraph dgraph = flatthelper.buildDirectGraph(root); DirectGraph dgraph = flatthelper.buildDirectGraph(root);
// try { // try {
// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot")); // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
// } catch(Exception ex) {ex.printStackTrace();} // } catch(Exception ex) {ex.printStackTrace();}
HashSet<Integer> setInit = new HashSet<Integer>(); HashSet<Integer> setInit = new HashSet<Integer>();
for(int i=0;i<64;i++) { for(int i = 0; i < 64; i++) {
setInit.add(i); setInit.add(i);
} }
factory = new FastSparseSetFactory<Integer>(setInit); factory = new FastSparseSetFactory<Integer>(setInit);
@ -85,19 +87,29 @@ public class SSAConstructorSparseEx {
HashSet<String> updated = new HashSet<String>(); HashSet<String> updated = new HashSet<String>();
do { do {
// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
ssaStatements(dgraph, updated); ssaStatements(dgraph, updated);
// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
} while(!updated.isEmpty()); } while (!updated.isEmpty());
} }
private void ssaStatements(DirectGraph dgraph, HashSet<String> updated) { private void ssaStatements(DirectGraph dgraph, HashSet<String> updated) {
// try { // try {
// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot")); // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
// } catch(Exception ex) {ex.printStackTrace();} // } catch(Exception ex) {ex.printStackTrace();}
for(DirectNode node: dgraph.nodes) { for(DirectNode node : dgraph.nodes) {
// if (node.id.endsWith("_inc")) {
// System.out.println();
//
// try {
// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
// } catch (Exception ex) {
// ex.printStackTrace();
// }
// }
updated.remove(node.id); updated.remove(node.id);
mergeInVarMaps(node, dgraph); mergeInVarMaps(node, dgraph);
@ -105,28 +117,28 @@ public class SSAConstructorSparseEx {
SFormsFastMapDirect varmap = inVarVersions.get(node.id); SFormsFastMapDirect varmap = inVarVersions.get(node.id);
varmap = new SFormsFastMapDirect(varmap); varmap = new SFormsFastMapDirect(varmap);
SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[] {varmap, null}; SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[] { varmap, null };
if(node.exprents != null) { if (node.exprents != null) {
for(Exprent expr: node.exprents) { for(Exprent expr : node.exprents) {
processExprent(expr, varmaparr); processExprent(expr, varmaparr);
} }
} }
if(varmaparr[1] == null) { if (varmaparr[1] == null) {
varmaparr[1] = varmaparr[0]; varmaparr[1] = varmaparr[0];
} }
boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id)) boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
|| (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id))); || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
if(this_updated) { if (this_updated) {
outVarVersions.put(node.id, varmaparr[0]); outVarVersions.put(node.id, varmaparr[0]);
if(dgraph.mapNegIfBranch.containsKey(node.id)) { if (dgraph.mapNegIfBranch.containsKey(node.id)) {
outNegVarVersions.put(node.id, varmaparr[1]); outNegVarVersions.put(node.id, varmaparr[1]);
} }
for(DirectNode nd: node.succs) { for(DirectNode nd : node.succs) {
updated.add(nd.id); updated.add(nd.id);
} }
} }
@ -136,32 +148,31 @@ public class SSAConstructorSparseEx {
private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr) { private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr) {
if(expr == null) { if (expr == null) {
return; return;
} }
VarExprent varassign = null; VarExprent varassign = null;
boolean finished = false; boolean finished = false;
switch(expr.type) { switch (expr.type) {
case Exprent.EXPRENT_ASSIGNMENT: case Exprent.EXPRENT_ASSIGNMENT:
AssignmentExprent assexpr = (AssignmentExprent)expr; AssignmentExprent assexpr = (AssignmentExprent) expr;
if(assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) { if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
Exprent dest = assexpr.getLeft(); Exprent dest = assexpr.getLeft();
if(dest.type == Exprent.EXPRENT_VAR) { if (dest.type == Exprent.EXPRENT_VAR) {
varassign = (VarExprent)dest; varassign = (VarExprent) dest;
} }
} }
break; break;
case Exprent.EXPRENT_FUNCTION: case Exprent.EXPRENT_FUNCTION:
FunctionExprent func = (FunctionExprent)expr; FunctionExprent func = (FunctionExprent) expr;
switch(func.getFunctype()) { switch (func.getFunctype()) {
case FunctionExprent.FUNCTION_IIF: case FunctionExprent.FUNCTION_IIF:
processExprent(func.getLstOperands().get(0), varmaparr); processExprent(func.getLstOperands().get(0), varmaparr);
SFormsFastMapDirect varmapFalse; SFormsFastMapDirect varmapFalse;
if(varmaparr[1] == null) { if (varmaparr[1] == null) {
varmapFalse = new SFormsFastMapDirect(varmaparr[0]); varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
} else { } else {
varmapFalse = varmaparr[1]; varmapFalse = varmaparr[1];
@ -170,7 +181,7 @@ public class SSAConstructorSparseEx {
processExprent(func.getLstOperands().get(1), varmaparr); processExprent(func.getLstOperands().get(1), varmaparr);
SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[] {varmapFalse, null}; SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[] { varmapFalse, null };
processExprent(func.getLstOperands().get(2), varmaparrNeg); processExprent(func.getLstOperands().get(2), varmaparrNeg);
mergeMaps(varmaparr[0], varmaparrNeg[0]); mergeMaps(varmaparr[0], varmaparrNeg[0]);
@ -181,12 +192,12 @@ public class SSAConstructorSparseEx {
case FunctionExprent.FUNCTION_CADD: case FunctionExprent.FUNCTION_CADD:
processExprent(func.getLstOperands().get(0), varmaparr); processExprent(func.getLstOperands().get(0), varmaparr);
SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[] {new SFormsFastMapDirect(varmaparr[0]), null}; SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[] { new SFormsFastMapDirect(varmaparr[0]), null };
processExprent(func.getLstOperands().get(1), varmaparrAnd); processExprent(func.getLstOperands().get(1), varmaparrAnd);
// false map // false map
varmaparr[1] = mergeMaps(varmaparr[varmaparr[1]==null?0:1], varmaparrAnd[varmaparrAnd[1]==null?0:1]); varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
// true map // true map
varmaparr[0] = varmaparrAnd[0]; varmaparr[0] = varmaparrAnd[0];
@ -195,12 +206,12 @@ public class SSAConstructorSparseEx {
case FunctionExprent.FUNCTION_COR: case FunctionExprent.FUNCTION_COR:
processExprent(func.getLstOperands().get(0), varmaparr); processExprent(func.getLstOperands().get(0), varmaparr);
SFormsFastMapDirect[] varmaparrOr = new SFormsFastMapDirect[] {new SFormsFastMapDirect(varmaparr[varmaparr[1]==null?0:1]), null}; SFormsFastMapDirect[] varmaparrOr = new SFormsFastMapDirect[] { new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null };
processExprent(func.getLstOperands().get(1), varmaparrOr); processExprent(func.getLstOperands().get(1), varmaparrOr);
// false map // false map
varmaparr[1] = varmaparrOr[varmaparrOr[1]==null?0:1]; varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
// true map // true map
varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]); varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
@ -208,26 +219,24 @@ public class SSAConstructorSparseEx {
} }
} }
if(finished) { if (finished) {
return; return;
} }
List<Exprent> lst = expr.getAllExprents(); List<Exprent> lst = expr.getAllExprents();
lst.remove(varassign); lst.remove(varassign);
for(Exprent ex: lst) { for(Exprent ex : lst) {
processExprent(ex, varmaparr); processExprent(ex, varmaparr);
} }
SFormsFastMapDirect varmap = varmaparr[0]; SFormsFastMapDirect varmap = varmaparr[0];
if(varassign != null) { if (varassign != null) {
Integer varindex = varassign.getIndex(); Integer varindex = varassign.getIndex();
if(varassign.getVersion() == 0) { if (varassign.getVersion() == 0) {
// get next version // get next version
Integer nextver = getNextFreeVersion(varindex); Integer nextver = getNextFreeVersion(varindex);
@ -239,22 +248,22 @@ public class SSAConstructorSparseEx {
setCurrentVar(varmap, varindex, varassign.getVersion()); setCurrentVar(varmap, varindex, varassign.getVersion());
} }
} else if(expr.type == Exprent.EXPRENT_VAR) { } else if (expr.type == Exprent.EXPRENT_VAR) {
VarExprent vardest = (VarExprent)expr; VarExprent vardest = (VarExprent) expr;
Integer varindex = vardest.getIndex(); Integer varindex = vardest.getIndex();
FastSparseSet<Integer> vers = varmap.get(varindex); FastSparseSet<Integer> vers = varmap.get(varindex);
int cardinality = vers.getCardinality(); int cardinality = vers.getCardinality();
if(cardinality == 1) { // == 1 if (cardinality == 1) { // == 1
// set version // set version
Integer it = vers.iterator().next(); Integer it = vers.iterator().next();
vardest.setVersion(it.intValue()); vardest.setVersion(it.intValue());
} else if(cardinality == 2) { // size > 1 } else if (cardinality == 2) { // size > 1
Integer current_vers = vardest.getVersion(); Integer current_vers = vardest.getVersion();
VarVersionPaar currpaar = new VarVersionPaar(varindex, current_vers); VarVersionPaar currpaar = new VarVersionPaar(varindex, current_vers);
if(current_vers != 0 && phi.containsKey(currpaar)) { if (current_vers != 0 && phi.containsKey(currpaar)) {
setCurrentVar(varmap, varindex, current_vers); setCurrentVar(varmap, varindex, current_vers);
// update phi node // update phi node
phi.get(currpaar).union(vers); phi.get(currpaar).union(vers);
@ -275,10 +284,10 @@ public class SSAConstructorSparseEx {
private Integer getNextFreeVersion(Integer var) { private Integer getNextFreeVersion(Integer var) {
Integer nextver = lastversion.get(var); Integer nextver = lastversion.get(var);
if(nextver==null) { if (nextver == null) {
nextver = new Integer(1); nextver = new Integer(1);
} else { } else {
nextver = new Integer(nextver.intValue()+1); nextver = new Integer(nextver.intValue() + 1);
} }
lastversion.put(var, nextver); lastversion.put(var, nextver);
return nextver; return nextver;
@ -288,18 +297,18 @@ public class SSAConstructorSparseEx {
SFormsFastMapDirect mapNew = new SFormsFastMapDirect(); SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
for(DirectNode pred: node.preds) { for(DirectNode pred : node.preds) {
SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id); SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
if(mapNew.isEmpty()) { if (mapNew.isEmpty()) {
mapNew = mapOut.getCopy(); mapNew = mapOut.getCopy();
} else { } else {
mergeMaps(mapNew, mapOut); mergeMaps(mapNew, mapOut);
} }
} }
if(extraVarVersions.containsKey(node.id)) { if (extraVarVersions.containsKey(node.id)) {
SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id); SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
if(mapNew.isEmpty()) { if (mapNew.isEmpty()) {
mapNew = mapExtra.getCopy(); mapNew = mapExtra.getCopy();
} else { } else {
mergeMaps(mapNew, mapExtra); mergeMaps(mapNew, mapExtra);
@ -309,22 +318,21 @@ public class SSAConstructorSparseEx {
inVarVersions.put(node.id, mapNew); inVarVersions.put(node.id, mapNew);
} }
private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
String destid) {
SFormsFastMapDirect mapNew = new SFormsFastMapDirect(); SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
if(nodeid.equals(dgraph.mapNegIfBranch.get(predid))) { if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
if(outNegVarVersions.containsKey(predid)) { if (outNegVarVersions.containsKey(predid)) {
mapNew = outNegVarVersions.get(predid).getCopy(); mapNew = outNegVarVersions.get(predid).getCopy();
} }
} else if(outVarVersions.containsKey(predid)) { } else if (outVarVersions.containsKey(predid)) {
mapNew = outVarVersions.get(predid).getCopy(); mapNew = outVarVersions.get(predid).getCopy();
} }
boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid); boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
if(isFinallyExit && !mapNew.isEmpty()) { if (isFinallyExit && !mapNew.isEmpty()) {
SFormsFastMapDirect mapNewTemp = mapNew.getCopy(); SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
@ -335,7 +343,7 @@ public class SSAConstructorSparseEx {
HashSet<String> setLongPathWrapper = new HashSet<String>(); HashSet<String> setLongPathWrapper = new HashSet<String>();
for(FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(predid)) { for(FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(predid)) {
setLongPathWrapper.add(finwraplong.destination+"##"+finwraplong.source); setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
} }
for(FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) { for(FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
@ -343,11 +351,11 @@ public class SSAConstructorSparseEx {
boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source); boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
if(recFinally) { if (recFinally) {
// recursion // recursion
map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid); map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
} else { } else {
if(finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) { if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
map = outNegVarVersions.get(finwrap.source); map = outNegVarVersions.get(finwrap.source);
} else { } else {
map = outVarVersions.get(finwrap.source); map = outVarVersions.get(finwrap.source);
@ -357,17 +365,17 @@ public class SSAConstructorSparseEx {
// false path? // false path?
boolean isFalsePath = true; boolean isFalsePath = true;
if(recFinally) { if (recFinally) {
isFalsePath = !finwrap.destination.equals(nodeid); isFalsePath = !finwrap.destination.equals(nodeid);
} else { } else {
isFalsePath = !setLongPathWrapper.contains(destid+"##"+finwrap.source); isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
} }
if(isFalsePath) { if (isFalsePath) {
mapNewTemp.complement(map); mapNewTemp.complement(map);
} else { } else {
if(mapTrueSource.isEmpty()) { if (mapTrueSource.isEmpty()) {
if(map != null) { if (map != null) {
mapTrueSource = map.getCopy(); mapTrueSource = map.getCopy();
} }
} else { } else {
@ -376,7 +384,7 @@ public class SSAConstructorSparseEx {
} }
} }
if(isExceptionMonitorExit) { if (isExceptionMonitorExit) {
mapNew = mapTrueSource; mapNew = mapTrueSource;
@ -385,7 +393,7 @@ public class SSAConstructorSparseEx {
mapNewTemp.union(mapTrueSource); mapNewTemp.union(mapTrueSource);
SFormsFastMapDirect oldInMap = inVarVersions.get(nodeid); SFormsFastMapDirect oldInMap = inVarVersions.get(nodeid);
if(oldInMap != null) { if (oldInMap != null) {
mapNewTemp.union(oldInMap); mapNewTemp.union(oldInMap);
} }
@ -396,10 +404,9 @@ public class SSAConstructorSparseEx {
return mapNew; return mapNew;
} }
private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) { private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
if(map2 != null && !map2.isEmpty()) { if (map2 != null && !map2.isEmpty()) {
mapTo.union(map2); mapTo.union(map2);
} }
@ -408,18 +415,18 @@ public class SSAConstructorSparseEx {
private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) { private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
if(map1 == null) { if (map1 == null) {
return map2 == null; return map2 == null;
} else if (map2 == null) { } else if (map2 == null) {
return false; return false;
} }
if(map1.size() != map2.size()) { if (map1.size() != map2.size()) {
return false; return false;
} }
for(Entry<Integer, FastSparseSet<Integer>> ent2: map2.entryList()) { for(Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
if(!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) { if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
return false; return false;
} }
} }
@ -427,7 +434,6 @@ public class SSAConstructorSparseEx {
return true; return true;
} }
private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) { private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
FastSparseSet<Integer> set = factory.spawnEmptySet(); FastSparseSet<Integer> set = factory.spawnEmptySet();
set.add(vers); set.add(vers);
@ -438,19 +444,19 @@ public class SSAConstructorSparseEx {
SFormsFastMapDirect map; SFormsFastMapDirect map;
switch(stat.type) { switch (stat.type) {
case Statement.TYPE_CATCHALL: case Statement.TYPE_CATCHALL:
case Statement.TYPE_TRYCATCH: case Statement.TYPE_TRYCATCH:
List<VarExprent> lstVars; List<VarExprent> lstVars;
if(stat.type == Statement.TYPE_CATCHALL) { if (stat.type == Statement.TYPE_CATCHALL) {
lstVars = ((CatchAllStatement)stat).getVars(); lstVars = ((CatchAllStatement) stat).getVars();
} else { } else {
lstVars = ((CatchStatement)stat).getVars(); lstVars = ((CatchStatement) stat).getVars();
} }
for(int i=1;i<stat.getStats().size();i++) { for(int i = 1; i < stat.getStats().size(); i++) {
int varindex = lstVars.get(i-1).getIndex(); int varindex = lstVars.get(i - 1).getIndex();
int version = getNextFreeVersion(varindex); // == 1 int version = getNextFreeVersion(varindex); // == 1
map = new SFormsFastMapDirect(); map = new SFormsFastMapDirect();
@ -461,7 +467,7 @@ public class SSAConstructorSparseEx {
} }
} }
for(Statement st: stat.getStats()) { for(Statement st : stat.getStats()) {
setCatchMaps(st, dgraph, flatthelper); setCatchMaps(st, dgraph, flatthelper);
} }
} }
@ -472,11 +478,11 @@ public class SSAConstructorSparseEx {
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
int paramcount = md.params.length + (thisvar?1:0); int paramcount = md.params.length + (thisvar ? 1 : 0);
int varindex = 0; int varindex = 0;
SFormsFastMapDirect map = new SFormsFastMapDirect(); SFormsFastMapDirect map = new SFormsFastMapDirect();
for(int i=0;i<paramcount;i++) { for(int i = 0; i < paramcount; i++) {
int version = getNextFreeVersion(varindex); // == 1 int version = getNextFreeVersion(varindex); // == 1
FastSparseSet<Integer> set = factory.spawnEmptySet(); FastSparseSet<Integer> set = factory.spawnEmptySet();
@ -484,14 +490,14 @@ public class SSAConstructorSparseEx {
map.put(varindex, set); map.put(varindex, set);
startVars.add(new VarVersionPaar(varindex, version)); startVars.add(new VarVersionPaar(varindex, version));
if(thisvar) { if (thisvar) {
if(i==0) { if (i == 0) {
varindex++; varindex++;
} else { } else {
varindex+=md.params[i-1].stack_size; varindex += md.params[i - 1].stack_size;
} }
} else { } else {
varindex+=md.params[i].stack_size; varindex += md.params[i].stack_size;
} }
} }

@ -110,9 +110,9 @@ public class SSAUConstructorSparseEx {
HashSet<String> updated = new HashSet<String>(); HashSet<String> updated = new HashSet<String>();
do { do {
// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); //System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
ssaStatements(dgraph, updated, false); ssaStatements(dgraph, updated, false);
// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava()); //System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
} while(!updated.isEmpty()); } while(!updated.isEmpty());
@ -146,6 +146,7 @@ public class SSAUConstructorSparseEx {
|| (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id))); || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
if(this_updated) { if(this_updated) {
outVarVersions.put(node.id, varmaparr[0]); outVarVersions.put(node.id, varmaparr[0]);
if(dgraph.mapNegIfBranch.containsKey(node.id)) { if(dgraph.mapNegIfBranch.containsKey(node.id)) {
outNegVarVersions.put(node.id, varmaparr[1]); outNegVarVersions.put(node.id, varmaparr[1]);
@ -246,45 +247,45 @@ public class SSAUConstructorSparseEx {
SFormsFastMapDirect varmap = varmaparr[0]; SFormsFastMapDirect varmap = varmaparr[0];
// field access // // field access
if(expr.type == Exprent.EXPRENT_FIELD) { // if(expr.type == Exprent.EXPRENT_FIELD) {
//
int index; // int index;
if(mapFieldVars.containsKey(expr.id)) { // if(mapFieldVars.containsKey(expr.id)) {
index = mapFieldVars.get(expr.id); // index = mapFieldVars.get(expr.id);
} else { // } else {
index = fieldvarcounter--; // index = fieldvarcounter--;
mapFieldVars.put(expr.id, index); // mapFieldVars.put(expr.id, index);
//
// ssu graph // // ssu graph
ssuversions.createNode(new VarVersionPaar(index, 1)); // ssuversions.createNode(new VarVersionPaar(index, 1));
} // }
//
setCurrentVar(varmap, index, 1); // setCurrentVar(varmap, index, 1);
//
} else if(expr.type == Exprent.EXPRENT_INVOCATION || // } else if(expr.type == Exprent.EXPRENT_INVOCATION ||
(expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) || // (expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) ||
(expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewtype().type == CodeConstants.TYPE_OBJECT) || // (expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewtype().type == CodeConstants.TYPE_OBJECT) ||
expr.type == Exprent.EXPRENT_FUNCTION) { // expr.type == Exprent.EXPRENT_FUNCTION) {
//
boolean ismmpp = true; // boolean ismmpp = true;
//
if(expr.type == Exprent.EXPRENT_FUNCTION) { // if(expr.type == Exprent.EXPRENT_FUNCTION) {
//
ismmpp = false; // ismmpp = false;
//
FunctionExprent fexpr = (FunctionExprent)expr; // FunctionExprent fexpr = (FunctionExprent)expr;
if(fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) { // if(fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) {
if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) { // if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
ismmpp = true; // ismmpp = true;
} // }
} // }
} // }
//
if(ismmpp) { // if(ismmpp) {
varmap.removeAllFields(); // varmap.removeAllFields();
} // }
} // }
if(varassign != null) { if(varassign != null) {

@ -22,6 +22,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import de.fernflower.code.CodeConstants;
import de.fernflower.struct.attr.StructGeneralAttribute; import de.fernflower.struct.attr.StructGeneralAttribute;
import de.fernflower.struct.consts.ConstantPool; import de.fernflower.struct.consts.ConstantPool;
import de.fernflower.struct.consts.PrimitiveConstant; import de.fernflower.struct.consts.PrimitiveConstant;
@ -318,4 +319,26 @@ public class StructClass {
return loader; return loader;
} }
public boolean isVersionGE_1_5() {
return (major_version > 48 || (major_version == 48 && minor_version > 0)); // FIXME: check second condition
}
public boolean isVersionGE_1_7() {
return (major_version >= 51);
}
public int getBytecodeVersion() {
switch(major_version) {
case 52:
return CodeConstants.BYTECODE_JAVA_8;
case 51:
return CodeConstants.BYTECODE_JAVA_7;
case 50:
return CodeConstants.BYTECODE_JAVA_6;
case 49:
return CodeConstants.BYTECODE_JAVA_5;
}
return CodeConstants.BYTECODE_JAVA_LE_4;
}
} }

@ -280,6 +280,8 @@ public class StructMethod implements CodeConstants {
VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>(); VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
int bytecode_version = classStruct.getBytecodeVersion();
for(int i=0;i<length;) { for(int i=0;i<length;) {
int offset = i; int offset = i;
@ -362,6 +364,14 @@ public class StructMethod implements CodeConstants {
group = GROUP_INVOCATION; group = GROUP_INVOCATION;
} }
break; break;
case opc_invokedynamic:
if(classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
operands.add(new Integer(in.readUnsignedShort()));
in.skip(2);
group = GROUP_INVOCATION;
i+=4;
}
break;
case opc_iload: case opc_iload:
case opc_lload: case opc_lload:
case opc_fload: case opc_fload:
@ -466,7 +476,7 @@ public class StructMethod implements CodeConstants {
ops[j] = ((Integer)operands.get(j)).intValue(); ops[j] = ((Integer)operands.get(j)).intValue();
} }
Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, ops); Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
collinstr.addWithKey(instr, new Integer(offset)); collinstr.addWithKey(instr, new Integer(offset));
@ -542,6 +552,9 @@ public class StructMethod implements CodeConstants {
return classStruct; return classStruct;
} }
public boolean containsCode() {
return containsCode;
}
} }

Loading…
Cancel
Save