summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStiver <stiver.mail@gmail.com>2014-03-13 23:02:30 +0100
committerStiver <stiver.mail@gmail.com>2014-03-13 23:02:30 +0100
commit96379678e6290428a7a0d840e8a62d8a9026beef (patch)
tree5b55f2c26bdce7272810fe448397ab7e07c2d6e8
parentc9c426ded7c91f7452f060a6d31e7ec5ff4731cf (diff)
downloadfernflower-96379678e6290428a7a0d840e8a62d8a9026beef.tar
fernflower-96379678e6290428a7a0d840e8a62d8a9026beef.tar.gz
fernflower-96379678e6290428a7a0d840e8a62d8a9026beef.tar.lz
fernflower-96379678e6290428a7a0d840e8a62d8a9026beef.tar.xz
fernflower-96379678e6290428a7a0d840e8a62d8a9026beef.zip
- method attribute 'default' (Java 8)
- instruction 'invokedynamic' (Java 7) - bugfixing
-rw-r--r--src/de/fernflower/code/CodeConstants.java11
-rw-r--r--src/de/fernflower/code/ConstantsUtil.java19
-rw-r--r--src/de/fernflower/code/Instruction.java3
-rw-r--r--src/de/fernflower/code/interpreter/InstructionImpact.java21
-rw-r--r--src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java20
-rw-r--r--src/de/fernflower/main/ClassReference14Processor.java15
-rw-r--r--src/de/fernflower/main/ClassWriter.java5
-rw-r--r--src/de/fernflower/main/rels/MethodProcessorThread.java6
-rw-r--r--src/de/fernflower/modules/decompiler/ExprProcessor.java13
-rw-r--r--src/de/fernflower/modules/decompiler/FinallyProcessor.java57
-rw-r--r--src/de/fernflower/modules/decompiler/exps/InvocationExprent.java22
-rw-r--r--src/de/fernflower/modules/decompiler/sforms/FlattenStatementsHelper.java15
-rw-r--r--src/de/fernflower/modules/decompiler/sforms/SSAConstructorSparseEx.java392
-rw-r--r--src/de/fernflower/modules/decompiler/sforms/SSAUConstructorSparseEx.java83
-rw-r--r--src/de/fernflower/struct/StructClass.java23
-rw-r--r--src/de/fernflower/struct/StructMethod.java15
16 files changed, 419 insertions, 301 deletions
diff --git a/src/de/fernflower/code/CodeConstants.java b/src/de/fernflower/code/CodeConstants.java
index 90ed425..111b3fd 100644
--- a/src/de/fernflower/code/CodeConstants.java
+++ b/src/de/fernflower/code/CodeConstants.java
@@ -17,6 +17,16 @@ package de.fernflower.code;
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
// ----------------------------------------------------------------------
@@ -339,6 +349,7 @@ public interface CodeConstants {
public final static int opc_invokespecial = 183;
public final static int opc_invokestatic = 184;
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_new = 187;
public final static int opc_newarray = 188;
diff --git a/src/de/fernflower/code/ConstantsUtil.java b/src/de/fernflower/code/ConstantsUtil.java
index fda1c49..ed9c5bd 100644
--- a/src/de/fernflower/code/ConstantsUtil.java
+++ b/src/de/fernflower/code/ConstantsUtil.java
@@ -30,6 +30,7 @@ import de.fernflower.code.optinstructions.GOTO_W;
import de.fernflower.code.optinstructions.IINC;
import de.fernflower.code.optinstructions.ILOAD;
import de.fernflower.code.optinstructions.INSTANCEOF;
+import de.fernflower.code.optinstructions.INVOKEDYNAMIC;
import de.fernflower.code.optinstructions.INVOKEINTERFACE;
import de.fernflower.code.optinstructions.INVOKESPECIAL;
import de.fernflower.code.optinstructions.INVOKESTATIC;
@@ -58,17 +59,18 @@ public class ConstantsUtil {
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.group = group;
+ instr.bytecode_version = bytecode_version;
instr.setOperands(operands);
return instr;
}
- public static Instruction getInstructionInstance(int opcode) {
+ private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
try {
Instruction instr;
@@ -78,7 +80,13 @@ public class ConstantsUtil {
opcode == CodeConstants.opc_ifnonnull) {
instr = new IfInstruction();
} else {
+
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) {
instr = new Instruction();
} else {
@@ -282,7 +290,8 @@ public class ConstantsUtil {
"invokespecial", // "invokespecial",
"invokestatic", // "invokestatic",
"invokeinterface", // "invokeinterface",
- "xxxunusedxxx", // "xxxunusedxxx",
+ //"xxxunusedxxx", // "xxxunusedxxx", Java 6 and before
+ "invokedynamic", // "invokedynamic", Java 7 and later
"new", // "new",
"newarray", // "newarray",
"anewarray", // "anewarray",
@@ -487,7 +496,7 @@ public class ConstantsUtil {
INVOKESPECIAL.class, // "invokespecial",
INVOKESTATIC.class, // "invokestatic",
INVOKEINTERFACE.class, // "invokeinterface",
- null , // "xxxunusedxxx",
+ INVOKEDYNAMIC.class, // "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
NEW.class, // "new",
NEWARRAY.class, // "newarray",
ANEWARRAY.class, // "anewarray",
diff --git a/src/de/fernflower/code/Instruction.java b/src/de/fernflower/code/Instruction.java
index ad76fc0..e74c4e9 100644
--- a/src/de/fernflower/code/Instruction.java
+++ b/src/de/fernflower/code/Instruction.java
@@ -29,6 +29,7 @@ public class Instruction implements CodeConstants {
public boolean wide = false;
+ public int bytecode_version = BYTECODE_JAVA_LE_4;
// *****************************************************************************
// private fields
@@ -55,7 +56,7 @@ public class Instruction implements CodeConstants {
}
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() {
diff --git a/src/de/fernflower/code/interpreter/InstructionImpact.java b/src/de/fernflower/code/interpreter/InstructionImpact.java
index 7d7e9e3..588991e 100644
--- a/src/de/fernflower/code/interpreter/InstructionImpact.java
+++ b/src/de/fernflower/code/interpreter/InstructionImpact.java
@@ -413,15 +413,18 @@ public class InstructionImpact {
case CodeConstants.opc_invokeinterface:
stack.pop();
case CodeConstants.opc_invokestatic:
- ck = pool.getLinkConstant(instr.getOperand(0));
- MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
- for(int i=0;i<md.params.length;i++) {
- stack.pop(md.params[i].stack_size);
- }
- if(md.ret.type != CodeConstants.TYPE_VOID) {
- stack.push(md.ret);
- if(md.ret.stack_size==2) {
- stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ case CodeConstants.opc_invokedynamic:
+ if(instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
+ for(int i=0;i<md.params.length;i++) {
+ stack.pop(md.params[i].stack_size);
+ }
+ if(md.ret.type != CodeConstants.TYPE_VOID) {
+ stack.push(md.ret);
+ if(md.ret.stack_size==2) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
}
}
break;
diff --git a/src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java b/src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java
new file mode 100644
index 0000000..488e1a6
--- /dev/null
+++ b/src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java
@@ -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;
+ }
+}
diff --git a/src/de/fernflower/main/ClassReference14Processor.java b/src/de/fernflower/main/ClassReference14Processor.java
index acaea12..2f4e6ab 100644
--- a/src/de/fernflower/main/ClassReference14Processor.java
+++ b/src/de/fernflower/main/ClassReference14Processor.java
@@ -95,15 +95,18 @@ public class ClassReference14Processor {
ClassWrapper wrapper = node.wrapper;
- int major_version = wrapper.getClassStruct().major_version;
- int minor_version = wrapper.getClassStruct().minor_version;
-
- if(major_version > 48 || (major_version == 48 && minor_version > 0)) {
+// int major_version = wrapper.getClassStruct().major_version;
+// int minor_version = wrapper.getClassStruct().minor_version;
+//
+// 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
return;
}
-
-
// find the synthetic method Class class$(String) if present
HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
diff --git a/src/de/fernflower/main/ClassWriter.java b/src/de/fernflower/main/ClassWriter.java
index 66fbea1..4e49f20 100644
--- a/src/de/fernflower/main/ClassWriter.java
+++ b/src/de/fernflower/main/ClassWriter.java
@@ -586,6 +586,11 @@ public class ClassWriter {
}
}
}
+
+ // 'default' modifier (Java 8)
+ if(isInterface && mt.containsCode()) {
+ bufstrwriter.write("default ");
+ }
GenericMethodDescriptor descriptor = null;
if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
diff --git a/src/de/fernflower/main/rels/MethodProcessorThread.java b/src/de/fernflower/main/rels/MethodProcessorThread.java
index ca789ed..a651e71 100644
--- a/src/de/fernflower/main/rels/MethodProcessorThread.java
+++ b/src/de/fernflower/main/rels/MethodProcessorThread.java
@@ -102,7 +102,7 @@ public class MethodProcessorThread implements Runnable {
// 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);
graph.inlineJsr(mt);
@@ -142,7 +142,7 @@ public class MethodProcessorThread implements Runnable {
DecompilerContext.getCountercontainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
- System.out.println(graph.toString());
+ //System.out.println(graph.toString());
if(ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
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);
//System.out.println(graph.toString());
- System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
root = DomHelper.parseGraph(graph);
}
diff --git a/src/de/fernflower/modules/decompiler/ExprProcessor.java b/src/de/fernflower/modules/decompiler/ExprProcessor.java
index a9a9878..c640bc1 100644
--- a/src/de/fernflower/modules/decompiler/ExprProcessor.java
+++ b/src/de/fernflower/modules/decompiler/ExprProcessor.java
@@ -527,11 +527,14 @@ public class ExprProcessor implements CodeConstants {
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
- InvocationExprent exprinv = new InvocationExprent(instr.opcode, pool.getLinkConstant(instr.getOperand(0)), stack);
- if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
- exprlist.add(exprinv);
- } else {
- pushEx(stack, exprlist, exprinv);
+ case opc_invokedynamic:
+ if(instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
+ InvocationExprent exprinv = new InvocationExprent(instr.opcode, pool.getLinkConstant(instr.getOperand(0)), stack);
+ if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
+ exprlist.add(exprinv);
+ } else {
+ pushEx(stack, exprlist, exprinv);
+ }
}
break;
case opc_new:
diff --git a/src/de/fernflower/modules/decompiler/FinallyProcessor.java b/src/de/fernflower/modules/decompiler/FinallyProcessor.java
index 0d8d556..cf10f48 100644
--- a/src/de/fernflower/modules/decompiler/FinallyProcessor.java
+++ b/src/de/fernflower/modules/decompiler/FinallyProcessor.java
@@ -14,16 +14,13 @@
package de.fernflower.modules.decompiler;
-import java.io.File;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
-import test.util.DotExporter;
import de.fernflower.code.CodeConstants;
import de.fernflower.code.ConstantsUtil;
import de.fernflower.code.Instruction;
@@ -73,6 +70,8 @@ public class FinallyProcessor {
private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
+ int bytecode_version = mt.getClassStruct().getBytecodeVersion();
+
LinkedList<Statement> stack = new LinkedList<Statement>();
stack.add(root);
@@ -110,7 +109,7 @@ public class FinallyProcessor {
} else {
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);
}
@@ -360,7 +359,7 @@ public class FinallyProcessor {
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);
@@ -389,8 +388,8 @@ public class FinallyProcessor {
// disable semaphore
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_istore, false, CodeConstants.GROUP_GENERAL, new int[]{var}) , -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, bytecode_version, new int[]{var}) , -1);
// build a separate block
BasicBlock newblock = new BasicBlock(++graph.last_id);
@@ -419,8 +418,8 @@ public class FinallyProcessor {
// enable semaphor at the statement entrance
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_istore, false, CodeConstants.GROUP_GENERAL, new int[]{var}) , -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, bytecode_version, new int[]{var}) , -1);
BasicBlock newhead = new BasicBlock(++graph.last_id);
newhead.setSeq(seq);
@@ -429,8 +428,8 @@ public class FinallyProcessor {
// initialize semaphor with false
seq = new SimpleInstructionSequence();
- seq.addInstruction(ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, 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_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}) , -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);
newheadinit.setSeq(seq);
@@ -566,9 +565,9 @@ public class FinallyProcessor {
lstAreas.add(new Object[] {start, arr[0], arr[1]});
}
- try {
- DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
- } catch(Exception ex){ex.printStackTrace();}
+// try {
+// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+// } catch(Exception ex){ex.printStackTrace();}
// delete areas
for(Object[] area: lstAreas) {
@@ -941,25 +940,25 @@ public class FinallyProcessor {
// remove all the blocks inbetween
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)
// can belong to more than one area
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
if(block.getSeq().isEmpty() && block.getSuccs().size() == 1) {
BasicBlock succs = block.getSuccs().get(0);
diff --git a/src/de/fernflower/modules/decompiler/exps/InvocationExprent.java b/src/de/fernflower/modules/decompiler/exps/InvocationExprent.java
index ee0a798..5f0f5c1 100644
--- a/src/de/fernflower/modules/decompiler/exps/InvocationExprent.java
+++ b/src/de/fernflower/modules/decompiler/exps/InvocationExprent.java
@@ -43,6 +43,7 @@ public class InvocationExprent extends Exprent {
public static final int INVOKE_VIRTUAL = 2;
public static final int INVOKE_STATIC = 3;
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_INIT = 2;
@@ -93,6 +94,10 @@ public class InvocationExprent extends Exprent {
break;
case CodeConstants.opc_invokeinterface:
invocationTyp = INVOKE_INTERFACE;
+ break;
+ case CodeConstants.opc_invokedynamic:
+ invocationTyp = INVOKE_DYNAMIC;
+ classname = "java/lang/Class"; // dummy class name
}
if("<init>".equals(name)) {
@@ -108,7 +113,7 @@ public class InvocationExprent extends Exprent {
lstParameters.add(0, stack.pop());
}
- if(opcode == CodeConstants.opc_invokestatic) {
+ if(opcode == CodeConstants.opc_invokestatic || opcode == CodeConstants.opc_invokedynamic) {
isStatic = true;
} else {
instance = stack.pop();
@@ -174,9 +179,11 @@ public class InvocationExprent extends Exprent {
boolean isInstanceThis = false;
if(isStatic) {
- ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
- if(node == null || !classname.equals(node.classStruct.qualifiedName)) {
- buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+ if(invocationTyp != INVOKE_DYNAMIC) {
+ ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ if(node == null || !classname.equals(node.classStruct.qualifiedName)) {
+ buf.append(DecompilerContext.getImpcollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+ }
}
} else {
@@ -249,7 +256,12 @@ public class InvocationExprent extends Exprent {
buf.append(".");
}
- buf.append(name+"(");
+ buf.append(name);
+ if(invocationTyp == INVOKE_DYNAMIC) {
+ buf.append("<invokedynamic>");
+ }
+ buf.append("(");
+
break;
case TYP_CLINIT:
throw new RuntimeException("Explicite invocation of <clinit>");
diff --git a/src/de/fernflower/modules/decompiler/sforms/FlattenStatementsHelper.java b/src/de/fernflower/modules/decompiler/sforms/FlattenStatementsHelper.java
index 8fd1fce..b73a45e 100644
--- a/src/de/fernflower/modules/decompiler/sforms/FlattenStatementsHelper.java
+++ b/src/de/fernflower/modules/decompiler/sforms/FlattenStatementsHelper.java
@@ -408,17 +408,19 @@ public class FlattenStatementsHelper {
if(finallyShortRangeSource != null) {
+ boolean isContinueEdge = (edgetype == StatEdge.TYPE_CONTINUE);
+
List<String[]> lst = mapShortRangeFinallyPathIds.get(sourcenode.id);
if(lst == null) {
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);
if(lst == null) {
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();
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]);
newLst.add(new FinallyPathWrapper(arr[0], dest.id, enter.id));
@@ -505,6 +510,10 @@ public class FlattenStatementsHelper {
public int hashCode() {
return (source+":"+destination+":"+entry).hashCode();
}
+
+ public String toString() {
+ return source + "->(" + entry + ")->" + destination;
+ }
}
diff --git a/src/de/fernflower/modules/decompiler/sforms/SSAConstructorSparseEx.java b/src/de/fernflower/modules/decompiler/sforms/SSAConstructorSparseEx.java
index 8db2fa7..528129c 100644
--- a/src/de/fernflower/modules/decompiler/sforms/SSAConstructorSparseEx.java
+++ b/src/de/fernflower/modules/decompiler/sforms/SSAConstructorSparseEx.java
@@ -14,12 +14,14 @@
package de.fernflower.modules.decompiler.sforms;
+import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
+import test.util.DotExporter;
import de.fernflower.code.CodeConstants;
import de.fernflower.modules.decompiler.exps.AssignmentExprent;
import de.fernflower.modules.decompiler.exps.Exprent;
@@ -34,134 +36,143 @@ import de.fernflower.modules.decompiler.vars.VarVersionPaar;
import de.fernflower.struct.StructMethod;
import de.fernflower.struct.gen.MethodDescriptor;
import de.fernflower.util.FastSparseSetFactory;
+import de.fernflower.util.FastSparseSetFactory.FastSparseSet;
import de.fernflower.util.InterpreterUtil;
import de.fernflower.util.SFormsFastMapDirect;
-import de.fernflower.util.FastSparseSetFactory.FastSparseSet;
public class SSAConstructorSparseEx {
// node id, var, version
private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
+
// node id, var, version (direct branch)
private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
// node id, var, version (negative branch)
private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
+
// node id, var, version
private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
-
+
// (var, version), version
- private HashMap<VarVersionPaar, FastSparseSet<Integer>> phi = new HashMap<VarVersionPaar, FastSparseSet<Integer>>();
-
+ private HashMap<VarVersionPaar, FastSparseSet<Integer>> phi = new HashMap<VarVersionPaar, FastSparseSet<Integer>>();
+
// var, version
- private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
-
+ private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
+
private List<VarVersionPaar> startVars = new ArrayList<VarVersionPaar>();
// set factory
private FastSparseSetFactory<Integer> factory;
-
+
public void splitVariables(RootStatement root, StructMethod mt) {
-
+
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
-
-// try {
-// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
-// } catch(Exception ex) {ex.printStackTrace();}
-
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
HashSet<Integer> setInit = new HashSet<Integer>();
- for(int i=0;i<64;i++) {
+ for(int i = 0; i < 64; i++) {
setInit.add(i);
}
factory = new FastSparseSetFactory<Integer>(setInit);
-
- SFormsFastMapDirect firstmap = createFirstMap(mt);
+
+ SFormsFastMapDirect firstmap = createFirstMap(mt);
extraVarVersions.put(dgraph.first.id, firstmap);
-
+
setCatchMaps(root, dgraph, flatthelper);
-
+
HashSet<String> updated = new HashSet<String>();
do {
-// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
ssaStatements(dgraph, updated);
-// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
- } while(!updated.isEmpty());
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ } while (!updated.isEmpty());
}
-
+
private void ssaStatements(DirectGraph dgraph, HashSet<String> updated) {
-
-// try {
-// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
-// } catch(Exception ex) {ex.printStackTrace();}
-
- for(DirectNode node: dgraph.nodes) {
-
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ 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);
mergeInVarMaps(node, dgraph);
-
+
SFormsFastMapDirect varmap = inVarVersions.get(node.id);
varmap = new SFormsFastMapDirect(varmap);
-
- SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[] {varmap, null};
-
- if(node.exprents != null) {
- for(Exprent expr: node.exprents) {
+
+ SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[] { varmap, null };
+
+ if (node.exprents != null) {
+ for(Exprent expr : node.exprents) {
processExprent(expr, varmaparr);
}
}
-
- if(varmaparr[1] == null) {
+
+ if (varmaparr[1] == null) {
varmaparr[1] = varmaparr[0];
}
-
+
boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
- || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
-
- if(this_updated) {
+ || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
+
+ if (this_updated) {
outVarVersions.put(node.id, varmaparr[0]);
- if(dgraph.mapNegIfBranch.containsKey(node.id)) {
+ if (dgraph.mapNegIfBranch.containsKey(node.id)) {
outNegVarVersions.put(node.id, varmaparr[1]);
}
-
- for(DirectNode nd: node.succs) {
+
+ for(DirectNode nd : node.succs) {
updated.add(nd.id);
}
}
}
-
+
}
-
+
private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr) {
-
- if(expr == null) {
+
+ if (expr == null) {
return;
}
-
-
- VarExprent varassign = null;
+
+ VarExprent varassign = null;
boolean finished = false;
-
- switch(expr.type) {
+
+ switch (expr.type) {
case Exprent.EXPRENT_ASSIGNMENT:
- AssignmentExprent assexpr = (AssignmentExprent)expr;
- if(assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
+ AssignmentExprent assexpr = (AssignmentExprent) expr;
+ if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
Exprent dest = assexpr.getLeft();
- if(dest.type == Exprent.EXPRENT_VAR) {
- varassign = (VarExprent)dest;
+ if (dest.type == Exprent.EXPRENT_VAR) {
+ varassign = (VarExprent) dest;
}
}
break;
case Exprent.EXPRENT_FUNCTION:
- FunctionExprent func = (FunctionExprent)expr;
- switch(func.getFunctype()) {
+ FunctionExprent func = (FunctionExprent) expr;
+ switch (func.getFunctype()) {
case FunctionExprent.FUNCTION_IIF:
processExprent(func.getLstOperands().get(0), varmaparr);
SFormsFastMapDirect varmapFalse;
- if(varmaparr[1] == null) {
+ if (varmaparr[1] == null) {
varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
} else {
varmapFalse = varmaparr[1];
@@ -169,92 +180,90 @@ public class SSAConstructorSparseEx {
}
processExprent(func.getLstOperands().get(1), varmaparr);
-
- SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[] {varmapFalse, null};
+
+ SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[] { varmapFalse, null };
processExprent(func.getLstOperands().get(2), varmaparrNeg);
-
+
mergeMaps(varmaparr[0], varmaparrNeg[0]);
varmaparr[1] = null;
-
- finished = true;
+
+ finished = true;
break;
case FunctionExprent.FUNCTION_CADD:
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);
-
+
// 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
varmaparr[0] = varmaparrAnd[0];
-
+
finished = true;
break;
case FunctionExprent.FUNCTION_COR:
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);
// false map
- varmaparr[1] = varmaparrOr[varmaparrOr[1]==null?0:1];
+ varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
// true map
varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
finished = true;
}
}
-
- if(finished) {
+
+ if (finished) {
return;
}
-
List<Exprent> lst = expr.getAllExprents();
lst.remove(varassign);
- for(Exprent ex: lst) {
+ for(Exprent ex : lst) {
processExprent(ex, varmaparr);
}
-
-
+
SFormsFastMapDirect varmap = varmaparr[0];
-
- if(varassign != null) {
-
+
+ if (varassign != null) {
+
Integer varindex = varassign.getIndex();
- if(varassign.getVersion() == 0) {
+ if (varassign.getVersion() == 0) {
// get next version
Integer nextver = getNextFreeVersion(varindex);
-
+
// set version
varassign.setVersion(nextver);
-
+
setCurrentVar(varmap, varindex, nextver);
} else {
setCurrentVar(varmap, varindex, varassign.getVersion());
}
-
- } else if(expr.type == Exprent.EXPRENT_VAR) {
-
- VarExprent vardest = (VarExprent)expr;
+
+ } else if (expr.type == Exprent.EXPRENT_VAR) {
+
+ VarExprent vardest = (VarExprent) expr;
Integer varindex = vardest.getIndex();
FastSparseSet<Integer> vers = varmap.get(varindex);
-
+
int cardinality = vers.getCardinality();
- if(cardinality == 1) { // == 1
+ if (cardinality == 1) { // == 1
// set version
Integer it = vers.iterator().next();
vardest.setVersion(it.intValue());
- } else if(cardinality == 2) { // size > 1
- Integer current_vers = vardest.getVersion();
-
+ } else if (cardinality == 2) { // size > 1
+ Integer current_vers = vardest.getVersion();
+
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);
// update phi node
phi.get(currpaar).union(vers);
@@ -263,111 +272,110 @@ public class SSAConstructorSparseEx {
Integer nextver = getNextFreeVersion(varindex);
// set version
vardest.setVersion(nextver);
-
+
setCurrentVar(varmap, varindex, nextver);
// create new phi node
phi.put(new VarVersionPaar(varindex, nextver), vers);
-
+
}
- } // 0 means uninitialized variable, which is impossible
+ } // 0 means uninitialized variable, which is impossible
}
}
-
+
private Integer getNextFreeVersion(Integer var) {
Integer nextver = lastversion.get(var);
- if(nextver==null) {
+ if (nextver == null) {
nextver = new Integer(1);
} else {
- nextver = new Integer(nextver.intValue()+1);
+ nextver = new Integer(nextver.intValue() + 1);
}
lastversion.put(var, nextver);
return nextver;
}
-
+
private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
-
+
SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
-
- for(DirectNode pred: node.preds) {
+
+ for(DirectNode pred : node.preds) {
SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
- if(mapNew.isEmpty()) {
+ if (mapNew.isEmpty()) {
mapNew = mapOut.getCopy();
} else {
mergeMaps(mapNew, mapOut);
}
}
-
- if(extraVarVersions.containsKey(node.id)) {
+
+ if (extraVarVersions.containsKey(node.id)) {
SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
- if(mapNew.isEmpty()) {
+ if (mapNew.isEmpty()) {
mapNew = mapExtra.getCopy();
} else {
mergeMaps(mapNew, mapExtra);
}
}
-
+
inVarVersions.put(node.id, mapNew);
}
-
- private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph,
- String destid) {
-
+
+ private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
+
SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
- if(nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
- if(outNegVarVersions.containsKey(predid)) {
+ if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
+ if (outNegVarVersions.containsKey(predid)) {
mapNew = outNegVarVersions.get(predid).getCopy();
}
- } else if(outVarVersions.containsKey(predid)) {
+ } else if (outVarVersions.containsKey(predid)) {
mapNew = outVarVersions.get(predid).getCopy();
}
-
+
boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
-
- if(isFinallyExit && !mapNew.isEmpty()) {
-
+
+ if (isFinallyExit && !mapNew.isEmpty()) {
+
SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
-
+
SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
-
+
String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
-
+
HashSet<String> setLongPathWrapper = new HashSet<String>();
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)) {
SFormsFastMapDirect map;
-
+
boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
-
- if(recFinally) {
+
+ if (recFinally) {
// recursion
- map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
+ map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
} else {
- if(finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
+ if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
map = outNegVarVersions.get(finwrap.source);
} else {
map = outVarVersions.get(finwrap.source);
}
}
-
+
// false path?
boolean isFalsePath = true;
-
- if(recFinally) {
+
+ if (recFinally) {
isFalsePath = !finwrap.destination.equals(nodeid);
} else {
- isFalsePath = !setLongPathWrapper.contains(destid+"##"+finwrap.source);
+ isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
}
-
- if(isFalsePath) {
+
+ if (isFalsePath) {
mapNewTemp.complement(map);
} else {
- if(mapTrueSource.isEmpty()) {
- if(map != null) {
+ if (mapTrueSource.isEmpty()) {
+ if (map != null) {
mapTrueSource = map.getCopy();
}
} else {
@@ -376,8 +384,8 @@ public class SSAConstructorSparseEx {
}
}
- if(isExceptionMonitorExit) {
-
+ if (isExceptionMonitorExit) {
+
mapNew = mapTrueSource;
} else {
@@ -385,119 +393,117 @@ public class SSAConstructorSparseEx {
mapNewTemp.union(mapTrueSource);
SFormsFastMapDirect oldInMap = inVarVersions.get(nodeid);
- if(oldInMap != null) {
+ if (oldInMap != null) {
mapNewTemp.union(oldInMap);
}
mapNew.intersection(mapNewTemp);
}
}
-
- return mapNew;
+
+ return mapNew;
}
-
-
+
private SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
-
- if(map2 != null && !map2.isEmpty()) {
+
+ if (map2 != null && !map2.isEmpty()) {
mapTo.union(map2);
}
-
+
return mapTo;
}
-
+
private boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
-
- if(map1 == null) {
+
+ if (map1 == null) {
return map2 == null;
} else if (map2 == null) {
return false;
}
-
- if(map1.size() != map2.size()) {
+
+ if (map1.size() != map2.size()) {
return false;
}
-
- for(Entry<Integer, FastSparseSet<Integer>> ent2: map2.entryList()) {
- if(!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
+
+ for(Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
+ if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
return false;
}
}
-
+
return true;
}
-
-
+
private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
FastSparseSet<Integer> set = factory.spawnEmptySet();
set.add(vers);
varmap.put(var, set);
}
-
+
private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
-
+
SFormsFastMapDirect map;
-
- switch(stat.type) {
+
+ switch (stat.type) {
case Statement.TYPE_CATCHALL:
case Statement.TYPE_TRYCATCH:
- List<VarExprent> lstVars;
- if(stat.type == Statement.TYPE_CATCHALL) {
- lstVars = ((CatchAllStatement)stat).getVars();
+ List<VarExprent> lstVars;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement) stat).getVars();
} else {
- lstVars = ((CatchStatement)stat).getVars();
+ lstVars = ((CatchStatement) stat).getVars();
}
-
- for(int i=1;i<stat.getStats().size();i++) {
- int varindex = lstVars.get(i-1).getIndex();
+
+ for(int i = 1; i < stat.getStats().size(); i++) {
+ int varindex = lstVars.get(i - 1).getIndex();
int version = getNextFreeVersion(varindex); // == 1
-
+
map = new SFormsFastMapDirect();
setCurrentVar(map, varindex, version);
-
+
extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
startVars.add(new VarVersionPaar(varindex, version));
}
}
-
- for(Statement st: stat.getStats()) {
+
+ for(Statement st : stat.getStats()) {
setCatchMaps(st, dgraph, flatthelper);
}
}
-
+
private SFormsFastMapDirect createFirstMap(StructMethod mt) {
-
+
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
-
+
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;
SFormsFastMapDirect map = new SFormsFastMapDirect();
- for(int i=0;i<paramcount;i++) {
+ for(int i = 0; i < paramcount; i++) {
int version = getNextFreeVersion(varindex); // == 1
-
+
FastSparseSet<Integer> set = factory.spawnEmptySet();
set.add(version);
map.put(varindex, set);
startVars.add(new VarVersionPaar(varindex, version));
-
- if(thisvar) {
- if(i==0) {
+
+ if (thisvar) {
+ if (i == 0) {
varindex++;
} else {
- varindex+=md.params[i-1].stack_size;
+ varindex += md.params[i - 1].stack_size;
}
} else {
- varindex+=md.params[i].stack_size;
+ varindex += md.params[i].stack_size;
}
}
-
+
return map;
}
-
+
public HashMap<VarVersionPaar, FastSparseSet<Integer>> getPhi() {
return phi;
}
@@ -505,5 +511,5 @@ public class SSAConstructorSparseEx {
public List<VarVersionPaar> getStartVars() {
return startVars;
}
-
+
}
diff --git a/src/de/fernflower/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/src/de/fernflower/modules/decompiler/sforms/SSAUConstructorSparseEx.java
index ec232fa..ef51e90 100644
--- a/src/de/fernflower/modules/decompiler/sforms/SSAUConstructorSparseEx.java
+++ b/src/de/fernflower/modules/decompiler/sforms/SSAUConstructorSparseEx.java
@@ -110,9 +110,9 @@ public class SSAUConstructorSparseEx {
HashSet<String> updated = new HashSet<String>();
do {
-// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ //System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
ssaStatements(dgraph, updated, false);
-// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ //System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
} while(!updated.isEmpty());
@@ -146,6 +146,7 @@ public class SSAUConstructorSparseEx {
|| (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
if(this_updated) {
+
outVarVersions.put(node.id, varmaparr[0]);
if(dgraph.mapNegIfBranch.containsKey(node.id)) {
outNegVarVersions.put(node.id, varmaparr[1]);
@@ -246,45 +247,45 @@ public class SSAUConstructorSparseEx {
SFormsFastMapDirect varmap = varmaparr[0];
- // field access
- if(expr.type == Exprent.EXPRENT_FIELD) {
-
- int index;
- if(mapFieldVars.containsKey(expr.id)) {
- index = mapFieldVars.get(expr.id);
- } else {
- index = fieldvarcounter--;
- mapFieldVars.put(expr.id, index);
-
- // ssu graph
- ssuversions.createNode(new VarVersionPaar(index, 1));
- }
-
- setCurrentVar(varmap, index, 1);
-
- } else if(expr.type == Exprent.EXPRENT_INVOCATION ||
- (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_FUNCTION) {
-
- boolean ismmpp = true;
-
- if(expr.type == Exprent.EXPRENT_FUNCTION) {
-
- ismmpp = false;
-
- FunctionExprent fexpr = (FunctionExprent)expr;
- if(fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) {
- if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
- ismmpp = true;
- }
- }
- }
-
- if(ismmpp) {
- varmap.removeAllFields();
- }
- }
+// // field access
+// if(expr.type == Exprent.EXPRENT_FIELD) {
+//
+// int index;
+// if(mapFieldVars.containsKey(expr.id)) {
+// index = mapFieldVars.get(expr.id);
+// } else {
+// index = fieldvarcounter--;
+// mapFieldVars.put(expr.id, index);
+//
+// // ssu graph
+// ssuversions.createNode(new VarVersionPaar(index, 1));
+// }
+//
+// setCurrentVar(varmap, index, 1);
+//
+// } else if(expr.type == Exprent.EXPRENT_INVOCATION ||
+// (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_FUNCTION) {
+//
+// boolean ismmpp = true;
+//
+// if(expr.type == Exprent.EXPRENT_FUNCTION) {
+//
+// ismmpp = false;
+//
+// FunctionExprent fexpr = (FunctionExprent)expr;
+// if(fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) {
+// if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
+// ismmpp = true;
+// }
+// }
+// }
+//
+// if(ismmpp) {
+// varmap.removeAllFields();
+// }
+// }
if(varassign != null) {
diff --git a/src/de/fernflower/struct/StructClass.java b/src/de/fernflower/struct/StructClass.java
index 75a55b1..de2e856 100644
--- a/src/de/fernflower/struct/StructClass.java
+++ b/src/de/fernflower/struct/StructClass.java
@@ -22,6 +22,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import de.fernflower.code.CodeConstants;
import de.fernflower.struct.attr.StructGeneralAttribute;
import de.fernflower.struct.consts.ConstantPool;
import de.fernflower.struct.consts.PrimitiveConstant;
@@ -318,4 +319,26 @@ public class StructClass {
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;
+ }
}
diff --git a/src/de/fernflower/struct/StructMethod.java b/src/de/fernflower/struct/StructMethod.java
index 3cc80c9..035fa68 100644
--- a/src/de/fernflower/struct/StructMethod.java
+++ b/src/de/fernflower/struct/StructMethod.java
@@ -280,6 +280,8 @@ public class StructMethod implements CodeConstants {
VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
+ int bytecode_version = classStruct.getBytecodeVersion();
+
for(int i=0;i<length;) {
int offset = i;
@@ -362,6 +364,14 @@ public class StructMethod implements CodeConstants {
group = GROUP_INVOCATION;
}
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_lload:
case opc_fload:
@@ -466,7 +476,7 @@ public class StructMethod implements CodeConstants {
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));
@@ -542,6 +552,9 @@ public class StructMethod implements CodeConstants {
return classStruct;
}
+ public boolean containsCode() {
+ return containsCode;
+ }
}