mirror of
https://hub.spigotmc.org/stash/scm/spigot/fernflower.git
synced 2025-09-18 22:14:39 +00:00
- method attribute 'default' (Java 8)
- instruction 'invokedynamic' (Java 7) - bugfixing
This commit is contained in:
parent
c9c426ded7
commit
96379678e6
16 changed files with 419 additions and 301 deletions
|
@ -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;
|
||||||
|
|
20
src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java
Normal file
20
src/de/fernflower/code/optinstructions/INVOKEDYNAMIC.java
Normal file
|
@ -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,15 +95,18 @@ 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>();
|
||||||
|
|
|
@ -586,6 +586,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)) {
|
||||||
|
|
|
@ -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,134 +36,143 @@ 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 {
|
||||||
|
|
||||||
// node id, var, version
|
// node id, var, version
|
||||||
private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
||||||
|
|
||||||
// node id, var, version (direct branch)
|
// node id, var, version (direct branch)
|
||||||
private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
||||||
|
|
||||||
// node id, var, version (negative branch)
|
// node id, var, version (negative branch)
|
||||||
private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
||||||
|
|
||||||
// node id, var, version
|
// node id, var, version
|
||||||
private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
||||||
|
|
||||||
// (var, version), version
|
// (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
|
// 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>();
|
private List<VarVersionPaar> startVars = new ArrayList<VarVersionPaar>();
|
||||||
|
|
||||||
// set factory
|
// set factory
|
||||||
private FastSparseSetFactory<Integer> factory;
|
private FastSparseSetFactory<Integer> factory;
|
||||||
|
|
||||||
public void splitVariables(RootStatement root, StructMethod mt) {
|
public void splitVariables(RootStatement root, StructMethod mt) {
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
SFormsFastMapDirect firstmap = createFirstMap(mt);
|
SFormsFastMapDirect firstmap = createFirstMap(mt);
|
||||||
extraVarVersions.put(dgraph.first.id, firstmap);
|
extraVarVersions.put(dgraph.first.id, firstmap);
|
||||||
|
|
||||||
setCatchMaps(root, dgraph, flatthelper);
|
setCatchMaps(root, dgraph, flatthelper);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
||||||
|
@ -169,92 +180,90 @@ 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]);
|
||||||
varmaparr[1] = null;
|
varmaparr[1] = null;
|
||||||
|
|
||||||
finished = true;
|
finished = true;
|
||||||
break;
|
break;
|
||||||
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];
|
||||||
|
|
||||||
finished = true;
|
finished = true;
|
||||||
break;
|
break;
|
||||||
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]);
|
||||||
|
|
||||||
finished = true;
|
finished = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
// set version
|
// set version
|
||||||
varassign.setVersion(nextver);
|
varassign.setVersion(nextver);
|
||||||
|
|
||||||
setCurrentVar(varmap, varindex, nextver);
|
setCurrentVar(varmap, varindex, nextver);
|
||||||
} else {
|
} else {
|
||||||
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);
|
||||||
|
@ -263,111 +272,110 @@ public class SSAConstructorSparseEx {
|
||||||
Integer nextver = getNextFreeVersion(varindex);
|
Integer nextver = getNextFreeVersion(varindex);
|
||||||
// set version
|
// set version
|
||||||
vardest.setVersion(nextver);
|
vardest.setVersion(nextver);
|
||||||
|
|
||||||
setCurrentVar(varmap, varindex, nextver);
|
setCurrentVar(varmap, varindex, nextver);
|
||||||
// create new phi node
|
// create new phi node
|
||||||
phi.put(new VarVersionPaar(varindex, nextver), vers);
|
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) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
|
private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
|
SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
|
||||||
|
|
||||||
String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
|
String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
|
||||||
boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
|
boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
|
||||||
|
|
||||||
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)) {
|
||||||
SFormsFastMapDirect map;
|
SFormsFastMapDirect map;
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,8 +384,8 @@ public class SSAConstructorSparseEx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isExceptionMonitorExit) {
|
if (isExceptionMonitorExit) {
|
||||||
|
|
||||||
mapNew = mapTrueSource;
|
mapNew = mapTrueSource;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -385,119 +393,117 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapNew.intersection(mapNewTemp);
|
mapNew.intersection(mapNewTemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapTo;
|
return mapTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
varmap.put(var, set);
|
varmap.put(var, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
|
private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
|
||||||
|
|
||||||
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();
|
||||||
setCurrentVar(map, varindex, version);
|
setCurrentVar(map, varindex, version);
|
||||||
|
|
||||||
extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
|
extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
|
||||||
startVars.add(new VarVersionPaar(varindex, version));
|
startVars.add(new VarVersionPaar(varindex, version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Statement st: stat.getStats()) {
|
for(Statement st : stat.getStats()) {
|
||||||
setCatchMaps(st, dgraph, flatthelper);
|
setCatchMaps(st, dgraph, flatthelper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SFormsFastMapDirect createFirstMap(StructMethod mt) {
|
private SFormsFastMapDirect createFirstMap(StructMethod mt) {
|
||||||
|
|
||||||
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
|
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
|
||||||
|
|
||||||
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();
|
||||||
set.add(version);
|
set.add(version);
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<VarVersionPaar, FastSparseSet<Integer>> getPhi() {
|
public HashMap<VarVersionPaar, FastSparseSet<Integer>> getPhi() {
|
||||||
return phi;
|
return phi;
|
||||||
}
|
}
|
||||||
|
@ -505,5 +511,5 @@ public class SSAConstructorSparseEx {
|
||||||
public List<VarVersionPaar> getStartVars() {
|
public List<VarVersionPaar> getStartVars() {
|
||||||
return startVars;
|
return startVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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…
Add table
Reference in a new issue