[*] Added a few gross patches to the intellij source tree
[*] Lazily moved intellijs source tree over
This commit is contained in:
parent
c6921030f4
commit
d4d5a1041b
23
pom.xml
23
pom.xml
@ -13,37 +13,20 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.spigotmc</groupId>
|
|
||||||
<artifactId>eclipse-formatter</artifactId>
|
|
||||||
<version>3.14.0-spigotmc-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<sourceDirectory>./src</sourceDirectory>
|
<sourceDirectory>./src</sourceDirectory>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>net.md-5</groupId>
|
|
||||||
<artifactId>determiner</artifactId>
|
|
||||||
<version>0.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>process-classes</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>transform</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.2</version>
|
<version>3.2</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.6</source>
|
<source>9</source>
|
||||||
<target>1.6</target>
|
<target>9</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -1,31 +1,22 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
|
@SuppressWarnings({"unused", "SpellCheckingInspection"})
|
||||||
public interface CodeConstants {
|
public interface CodeConstants {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// BYTECODE VERSIONS
|
// BYTECODE VERSIONS
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
int BYTECODE_JAVA_LE_4 = 1;
|
int BYTECODE_JAVA_LE_4 = 48;
|
||||||
int BYTECODE_JAVA_5 = 2;
|
int BYTECODE_JAVA_5 = 49;
|
||||||
int BYTECODE_JAVA_6 = 3;
|
int BYTECODE_JAVA_6 = 50;
|
||||||
int BYTECODE_JAVA_7 = 4;
|
int BYTECODE_JAVA_7 = 51;
|
||||||
int BYTECODE_JAVA_8 = 5;
|
int BYTECODE_JAVA_8 = 52;
|
||||||
|
int BYTECODE_JAVA_9 = 53;
|
||||||
|
int BYTECODE_JAVA_10 = 54;
|
||||||
|
int BYTECODE_JAVA_11 = 55;
|
||||||
|
int BYTECODE_JAVA_12 = 56;
|
||||||
|
int BYTECODE_JAVA_13 = 57;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// VARIABLE TYPES
|
// VARIABLE TYPES
|
||||||
@ -63,20 +54,6 @@ public interface CodeConstants {
|
|||||||
int TYPE_FAMILY_DOUBLE = 5;
|
int TYPE_FAMILY_DOUBLE = 5;
|
||||||
int TYPE_FAMILY_OBJECT = 6;
|
int TYPE_FAMILY_OBJECT = 6;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
// MODULE CONSTANTS
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
int STACKSIZE_SIMPLE = 1;
|
|
||||||
int STACKSIZE_DOUBLE = 2;
|
|
||||||
|
|
||||||
int VAR_LOCAL = 0;
|
|
||||||
int VAR_STACK = 1;
|
|
||||||
|
|
||||||
int VAR_WRITE = 0;
|
|
||||||
int VAR_READ = 1;
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// ACCESS FLAGS
|
// ACCESS FLAGS
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
@ -87,6 +64,7 @@ public interface CodeConstants {
|
|||||||
int ACC_STATIC = 0x0008;
|
int ACC_STATIC = 0x0008;
|
||||||
int ACC_FINAL = 0x0010;
|
int ACC_FINAL = 0x0010;
|
||||||
int ACC_SYNCHRONIZED = 0x0020;
|
int ACC_SYNCHRONIZED = 0x0020;
|
||||||
|
int ACC_OPEN = 0x0020;
|
||||||
int ACC_NATIVE = 0x0100;
|
int ACC_NATIVE = 0x0100;
|
||||||
int ACC_ABSTRACT = 0x0400;
|
int ACC_ABSTRACT = 0x0400;
|
||||||
int ACC_STRICT = 0x0800;
|
int ACC_STRICT = 0x0800;
|
||||||
@ -97,6 +75,8 @@ public interface CodeConstants {
|
|||||||
int ACC_SYNTHETIC = 0x1000;
|
int ACC_SYNTHETIC = 0x1000;
|
||||||
int ACC_ANNOTATION = 0x2000;
|
int ACC_ANNOTATION = 0x2000;
|
||||||
int ACC_ENUM = 0x4000;
|
int ACC_ENUM = 0x4000;
|
||||||
|
int ACC_MANDATED = 0x8000;
|
||||||
|
int ACC_MODULE = 0x8000;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// CLASS FLAGS
|
// CLASS FLAGS
|
||||||
@ -105,17 +85,6 @@ public interface CodeConstants {
|
|||||||
int ACC_SUPER = 0x0020;
|
int ACC_SUPER = 0x0020;
|
||||||
int ACC_INTERFACE = 0x0200;
|
int ACC_INTERFACE = 0x0200;
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
// DEPENDENCY CONSTANTS
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
int DEP_CONSTANT = 0;
|
|
||||||
int DEP_UNKNOWN = 1;
|
|
||||||
int DEP_GENERAL = 2;
|
|
||||||
int DEP_PARAMS = 4;
|
|
||||||
int DEP_STATIC = 8;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// INSTRUCTION GROUPS
|
// INSTRUCTION GROUPS
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
@ -145,6 +114,8 @@ public interface CodeConstants {
|
|||||||
int CONSTANT_MethodHandle = 15;
|
int CONSTANT_MethodHandle = 15;
|
||||||
int CONSTANT_MethodType = 16;
|
int CONSTANT_MethodType = 16;
|
||||||
int CONSTANT_InvokeDynamic = 18;
|
int CONSTANT_InvokeDynamic = 18;
|
||||||
|
int CONSTANT_Module = 19;
|
||||||
|
int CONSTANT_Package = 20;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// MethodHandle reference_kind values
|
// MethodHandle reference_kind values
|
||||||
@ -351,7 +322,6 @@ public interface CodeConstants {
|
|||||||
int opc_invokestatic = 184;
|
int opc_invokestatic = 184;
|
||||||
int opc_invokeinterface = 185;
|
int opc_invokeinterface = 185;
|
||||||
int opc_invokedynamic = 186;
|
int opc_invokedynamic = 186;
|
||||||
int opc_xxxunusedxxx = 186;
|
|
||||||
int opc_new = 187;
|
int opc_new = 187;
|
||||||
int opc_newarray = 188;
|
int opc_newarray = 188;
|
||||||
int opc_anewarray = 189;
|
int opc_anewarray = 189;
|
||||||
@ -367,4 +337,7 @@ public interface CodeConstants {
|
|||||||
int opc_ifnonnull = 199;
|
int opc_ifnonnull = 199;
|
||||||
int opc_goto_w = 200;
|
int opc_goto_w = 200;
|
||||||
int opc_jsr_w = 201;
|
int opc_jsr_w = 201;
|
||||||
}
|
|
||||||
|
String CLINIT_NAME = "<clinit>";
|
||||||
|
String INIT_NAME = "<init>";
|
||||||
|
}
|
@ -1,482 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.optinstructions.*;
|
|
||||||
|
|
||||||
public class ConstantsUtil {
|
|
||||||
|
|
||||||
public static String getName(int opcode) {
|
|
||||||
return opcodeNames[opcode];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int bytecode_version, int[] operands) {
|
|
||||||
|
|
||||||
Instruction instr = getInstructionInstance(opcode, bytecode_version);
|
|
||||||
instr.wide = wide;
|
|
||||||
instr.group = group;
|
|
||||||
instr.bytecode_version = bytecode_version;
|
|
||||||
instr.setOperands(operands);
|
|
||||||
|
|
||||||
return instr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
|
|
||||||
try {
|
|
||||||
Instruction instr;
|
|
||||||
|
|
||||||
if ((opcode >= CodeConstants.opc_ifeq &&
|
|
||||||
opcode <= CodeConstants.opc_if_acmpne) ||
|
|
||||||
opcode == CodeConstants.opc_ifnull ||
|
|
||||||
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 {
|
|
||||||
instr = (Instruction)cl.newInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instr.opcode = opcode;
|
|
||||||
return instr;
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static String[] opcodeNames = {
|
|
||||||
"nop", // "nop",
|
|
||||||
"aconst_null", // "aconst_null",
|
|
||||||
"iconst_m1", // "iconst_m1",
|
|
||||||
"iconst_0", // "iconst_0",
|
|
||||||
"iconst_1", // "iconst_1",
|
|
||||||
"iconst_2", // "iconst_2",
|
|
||||||
"iconst_3", // "iconst_3",
|
|
||||||
"iconst_4", // "iconst_4",
|
|
||||||
"iconst_5", // "iconst_5",
|
|
||||||
"lconst_0", // "lconst_0",
|
|
||||||
"lconst_1", // "lconst_1",
|
|
||||||
"fconst_0", // "fconst_0",
|
|
||||||
"fconst_1", // "fconst_1",
|
|
||||||
"fconst_2", // "fconst_2",
|
|
||||||
"dconst_0", // "dconst_0",
|
|
||||||
"dconst_1", // "dconst_1",
|
|
||||||
"bipush", // "bipush",
|
|
||||||
"sipush", // "sipush",
|
|
||||||
"ldc", // "ldc",
|
|
||||||
"ldc_w", // "ldc_w",
|
|
||||||
"ldc2_w", // "ldc2_w",
|
|
||||||
"iload", // "iload",
|
|
||||||
"lload", // "lload",
|
|
||||||
"fload", // "fload",
|
|
||||||
"dload", // "dload",
|
|
||||||
"aload", // "aload",
|
|
||||||
"iload_0", // "iload_0",
|
|
||||||
"iload_1", // "iload_1",
|
|
||||||
"iload_2", // "iload_2",
|
|
||||||
"iload_3", // "iload_3",
|
|
||||||
"lload_0", // "lload_0",
|
|
||||||
"lload_1", // "lload_1",
|
|
||||||
"lload_2", // "lload_2",
|
|
||||||
"lload_3", // "lload_3",
|
|
||||||
"fload_0", // "fload_0",
|
|
||||||
"fload_1", // "fload_1",
|
|
||||||
"fload_2", // "fload_2",
|
|
||||||
"fload_3", // "fload_3",
|
|
||||||
"dload_0", // "dload_0",
|
|
||||||
"dload_1", // "dload_1",
|
|
||||||
"dload_2", // "dload_2",
|
|
||||||
"dload_3", // "dload_3",
|
|
||||||
"aload_0", // "aload_0",
|
|
||||||
"aload_1", // "aload_1",
|
|
||||||
"aload_2", // "aload_2",
|
|
||||||
"aload_3", // "aload_3",
|
|
||||||
"iaload", // "iaload",
|
|
||||||
"laload", // "laload",
|
|
||||||
"faload", // "faload",
|
|
||||||
"daload", // "daload",
|
|
||||||
"aaload", // "aaload",
|
|
||||||
"baload", // "baload",
|
|
||||||
"caload", // "caload",
|
|
||||||
"saload", // "saload",
|
|
||||||
"istore", // "istore",
|
|
||||||
"lstore", // "lstore",
|
|
||||||
"fstore", // "fstore",
|
|
||||||
"dstore", // "dstore",
|
|
||||||
"astore", // "astore",
|
|
||||||
"istore_0", // "istore_0",
|
|
||||||
"istore_1", // "istore_1",
|
|
||||||
"istore_2", // "istore_2",
|
|
||||||
"istore_3", // "istore_3",
|
|
||||||
"lstore_0", // "lstore_0",
|
|
||||||
"lstore_1", // "lstore_1",
|
|
||||||
"lstore_2", // "lstore_2",
|
|
||||||
"lstore_3", // "lstore_3",
|
|
||||||
"fstore_0", // "fstore_0",
|
|
||||||
"fstore_1", // "fstore_1",
|
|
||||||
"fstore_2", // "fstore_2",
|
|
||||||
"fstore_3", // "fstore_3",
|
|
||||||
"dstore_0", // "dstore_0",
|
|
||||||
"dstore_1", // "dstore_1",
|
|
||||||
"dstore_2", // "dstore_2",
|
|
||||||
"dstore_3", // "dstore_3",
|
|
||||||
"astore_0", // "astore_0",
|
|
||||||
"astore_1", // "astore_1",
|
|
||||||
"astore_2", // "astore_2",
|
|
||||||
"astore_3", // "astore_3",
|
|
||||||
"iastore", // "iastore",
|
|
||||||
"lastore", // "lastore",
|
|
||||||
"fastore", // "fastore",
|
|
||||||
"dastore", // "dastore",
|
|
||||||
"aastore", // "aastore",
|
|
||||||
"bastore", // "bastore",
|
|
||||||
"castore", // "castore",
|
|
||||||
"sastore", // "sastore",
|
|
||||||
"pop", // "pop",
|
|
||||||
"pop2", // "pop2",
|
|
||||||
"dup", // "dup",
|
|
||||||
"dup_x1", // "dup_x1",
|
|
||||||
"dup_x2", // "dup_x2",
|
|
||||||
"dup2", // "dup2",
|
|
||||||
"dup2_x1", // "dup2_x1",
|
|
||||||
"dup2_x2", // "dup2_x2",
|
|
||||||
"swap", // "swap",
|
|
||||||
"iadd", // "iadd",
|
|
||||||
"ladd", // "ladd",
|
|
||||||
"fadd", // "fadd",
|
|
||||||
"dadd", // "dadd",
|
|
||||||
"isub", // "isub",
|
|
||||||
"lsub", // "lsub",
|
|
||||||
"fsub", // "fsub",
|
|
||||||
"dsub", // "dsub",
|
|
||||||
"imul", // "imul",
|
|
||||||
"lmul", // "lmul",
|
|
||||||
"fmul", // "fmul",
|
|
||||||
"dmul", // "dmul",
|
|
||||||
"idiv", // "idiv",
|
|
||||||
"ldiv", // "ldiv",
|
|
||||||
"fdiv", // "fdiv",
|
|
||||||
"ddiv", // "ddiv",
|
|
||||||
"irem", // "irem",
|
|
||||||
"lrem", // "lrem",
|
|
||||||
"frem", // "frem",
|
|
||||||
"drem", // "drem",
|
|
||||||
"ineg", // "ineg",
|
|
||||||
"lneg", // "lneg",
|
|
||||||
"fneg", // "fneg",
|
|
||||||
"dneg", // "dneg",
|
|
||||||
"ishl", // "ishl",
|
|
||||||
"lshl", // "lshl",
|
|
||||||
"ishr", // "ishr",
|
|
||||||
"lshr", // "lshr",
|
|
||||||
"iushr", // "iushr",
|
|
||||||
"lushr", // "lushr",
|
|
||||||
"iand", // "iand",
|
|
||||||
"land", // "land",
|
|
||||||
"ior", // "ior",
|
|
||||||
"lor", // "lor",
|
|
||||||
"ixor", // "ixor",
|
|
||||||
"lxor", // "lxor",
|
|
||||||
"iinc", // "iinc",
|
|
||||||
"i2l", // "i2l",
|
|
||||||
"i2f", // "i2f",
|
|
||||||
"i2d", // "i2d",
|
|
||||||
"l2i", // "l2i",
|
|
||||||
"l2f", // "l2f",
|
|
||||||
"l2d", // "l2d",
|
|
||||||
"f2i", // "f2i",
|
|
||||||
"f2l", // "f2l",
|
|
||||||
"f2d", // "f2d",
|
|
||||||
"d2i", // "d2i",
|
|
||||||
"d2l", // "d2l",
|
|
||||||
"d2f", // "d2f",
|
|
||||||
"i2b", // "i2b",
|
|
||||||
"i2c", // "i2c",
|
|
||||||
"i2s", // "i2s",
|
|
||||||
"lcmp", // "lcmp",
|
|
||||||
"fcmpl", // "fcmpl",
|
|
||||||
"fcmpg", // "fcmpg",
|
|
||||||
"dcmpl", // "dcmpl",
|
|
||||||
"dcmpg", // "dcmpg",
|
|
||||||
"ifeq", // "ifeq",
|
|
||||||
"ifne", // "ifne",
|
|
||||||
"iflt", // "iflt",
|
|
||||||
"ifge", // "ifge",
|
|
||||||
"ifgt", // "ifgt",
|
|
||||||
"ifle", // "ifle",
|
|
||||||
"if_icmpeq", // "if_icmpeq",
|
|
||||||
"if_icmpne", // "if_icmpne",
|
|
||||||
"if_icmplt", // "if_icmplt",
|
|
||||||
"if_icmpge", // "if_icmpge",
|
|
||||||
"if_icmpgt", // "if_icmpgt",
|
|
||||||
"if_icmple", // "if_icmple",
|
|
||||||
"if_acmpeq", // "if_acmpeq",
|
|
||||||
"if_acmpne", // "if_acmpne",
|
|
||||||
"goto", // "goto",
|
|
||||||
"jsr", // "jsr",
|
|
||||||
"ret", // "ret",
|
|
||||||
"tableswitch", // "tableswitch",
|
|
||||||
"lookupswitch", // "lookupswitch",
|
|
||||||
"ireturn", // "ireturn",
|
|
||||||
"lreturn", // "lreturn",
|
|
||||||
"freturn", // "freturn",
|
|
||||||
"dreturn", // "dreturn",
|
|
||||||
"areturn", // "areturn",
|
|
||||||
"return", // "return",
|
|
||||||
"getstatic", // "getstatic",
|
|
||||||
"putstatic", // "putstatic",
|
|
||||||
"getfield", // "getfield",
|
|
||||||
"putfield", // "putfield",
|
|
||||||
"invokevirtual", // "invokevirtual",
|
|
||||||
"invokespecial", // "invokespecial",
|
|
||||||
"invokestatic", // "invokestatic",
|
|
||||||
"invokeinterface", // "invokeinterface",
|
|
||||||
//"xxxunusedxxx", // "xxxunusedxxx", Java 6 and before
|
|
||||||
"invokedynamic", // "invokedynamic", Java 7 and later
|
|
||||||
"new", // "new",
|
|
||||||
"newarray", // "newarray",
|
|
||||||
"anewarray", // "anewarray",
|
|
||||||
"arraylength", // "arraylength",
|
|
||||||
"athrow", // "athrow",
|
|
||||||
"checkcast", // "checkcast",
|
|
||||||
"instanceof", // "instanceof",
|
|
||||||
"monitorenter", // "monitorenter",
|
|
||||||
"monitorexit", // "monitorexit",
|
|
||||||
"wide", // "wide",
|
|
||||||
"multianewarray", // "multianewarray",
|
|
||||||
"ifnull", // "ifnull",
|
|
||||||
"ifnonnull", // "ifnonnull",
|
|
||||||
"goto_w", // "goto_w",
|
|
||||||
"jsr_w" // "jsr_w"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static Class[] opcodeClasses = {
|
|
||||||
null, // "nop",
|
|
||||||
null, // "aconst_null",
|
|
||||||
null, // "iconst_m1",
|
|
||||||
null, // "iconst_0",
|
|
||||||
null, // "iconst_1",
|
|
||||||
null, // "iconst_2",
|
|
||||||
null, // "iconst_3",
|
|
||||||
null, // "iconst_4",
|
|
||||||
null, // "iconst_5",
|
|
||||||
null, // "lconst_0",
|
|
||||||
null, // "lconst_1",
|
|
||||||
null, // "fconst_0",
|
|
||||||
null, // "fconst_1",
|
|
||||||
null, // "fconst_2",
|
|
||||||
null, // "dconst_0",
|
|
||||||
null, // "dconst_1",
|
|
||||||
BIPUSH.class, // "bipush",
|
|
||||||
SIPUSH.class, // "sipush",
|
|
||||||
LDC.class, // "ldc",
|
|
||||||
LDC_W.class, // "ldc_w",
|
|
||||||
LDC2_W.class, // "ldc2_w",
|
|
||||||
ILOAD.class, // "iload",
|
|
||||||
LLOAD.class, // "lload",
|
|
||||||
FLOAD.class, // "fload",
|
|
||||||
DLOAD.class, // "dload",
|
|
||||||
ALOAD.class, // "aload",
|
|
||||||
null, // "iload_0",
|
|
||||||
null, // "iload_1",
|
|
||||||
null, // "iload_2",
|
|
||||||
null, // "iload_3",
|
|
||||||
null, // "lload_0",
|
|
||||||
null, // "lload_1",
|
|
||||||
null, // "lload_2",
|
|
||||||
null, // "lload_3",
|
|
||||||
null, // "fload_0",
|
|
||||||
null, // "fload_1",
|
|
||||||
null, // "fload_2",
|
|
||||||
null, // "fload_3",
|
|
||||||
null, // "dload_0",
|
|
||||||
null, // "dload_1",
|
|
||||||
null, // "dload_2",
|
|
||||||
null, // "dload_3",
|
|
||||||
null, // "aload_0",
|
|
||||||
null, // "aload_1",
|
|
||||||
null, // "aload_2",
|
|
||||||
null, // "aload_3",
|
|
||||||
null, // "iaload",
|
|
||||||
null, // "laload",
|
|
||||||
null, // "faload",
|
|
||||||
null, // "daload",
|
|
||||||
null, // "aaload",
|
|
||||||
null, // "baload",
|
|
||||||
null, // "caload",
|
|
||||||
null, // "saload",
|
|
||||||
ISTORE.class, // "istore",
|
|
||||||
LSTORE.class, // "lstore",
|
|
||||||
FSTORE.class, // "fstore",
|
|
||||||
DSTORE.class, // "dstore",
|
|
||||||
ASTORE.class, // "astore",
|
|
||||||
null, // "istore_0",
|
|
||||||
null, // "istore_1",
|
|
||||||
null, // "istore_2",
|
|
||||||
null, // "istore_3",
|
|
||||||
null, // "lstore_0",
|
|
||||||
null, // "lstore_1",
|
|
||||||
null, // "lstore_2",
|
|
||||||
null, // "lstore_3",
|
|
||||||
null, // "fstore_0",
|
|
||||||
null, // "fstore_1",
|
|
||||||
null, // "fstore_2",
|
|
||||||
null, // "fstore_3",
|
|
||||||
null, // "dstore_0",
|
|
||||||
null, // "dstore_1",
|
|
||||||
null, // "dstore_2",
|
|
||||||
null, // "dstore_3",
|
|
||||||
null, // "astore_0",
|
|
||||||
null, // "astore_1",
|
|
||||||
null, // "astore_2",
|
|
||||||
null, // "astore_3",
|
|
||||||
null, // "iastore",
|
|
||||||
null, // "lastore",
|
|
||||||
null, // "fastore",
|
|
||||||
null, // "dastore",
|
|
||||||
null, // "aastore",
|
|
||||||
null, // "bastore",
|
|
||||||
null, // "castore",
|
|
||||||
null, // "sastore",
|
|
||||||
null, // "pop",
|
|
||||||
null, // "pop2",
|
|
||||||
null, // "dup",
|
|
||||||
null, // "dup_x1",
|
|
||||||
null, // "dup_x2",
|
|
||||||
null, // "dup2",
|
|
||||||
null, // "dup2_x1",
|
|
||||||
null, // "dup2_x2",
|
|
||||||
null, // "swap",
|
|
||||||
null, // "iadd",
|
|
||||||
null, // "ladd",
|
|
||||||
null, // "fadd",
|
|
||||||
null, // "dadd",
|
|
||||||
null, // "isub",
|
|
||||||
null, // "lsub",
|
|
||||||
null, // "fsub",
|
|
||||||
null, // "dsub",
|
|
||||||
null, // "imul",
|
|
||||||
null, // "lmul",
|
|
||||||
null, // "fmul",
|
|
||||||
null, // "dmul",
|
|
||||||
null, // "idiv",
|
|
||||||
null, // "ldiv",
|
|
||||||
null, // "fdiv",
|
|
||||||
null, // "ddiv",
|
|
||||||
null, // "irem",
|
|
||||||
null, // "lrem",
|
|
||||||
null, // "frem",
|
|
||||||
null, // "drem",
|
|
||||||
null, // "ineg",
|
|
||||||
null, // "lneg",
|
|
||||||
null, // "fneg",
|
|
||||||
null, // "dneg",
|
|
||||||
null, // "ishl",
|
|
||||||
null, // "lshl",
|
|
||||||
null, // "ishr",
|
|
||||||
null, // "lshr",
|
|
||||||
null, // "iushr",
|
|
||||||
null, // "lushr",
|
|
||||||
null, // "iand",
|
|
||||||
null, // "land",
|
|
||||||
null, // "ior",
|
|
||||||
null, // "lor",
|
|
||||||
null, // "ixor",
|
|
||||||
null, // "lxor",
|
|
||||||
IINC.class, // "iinc",
|
|
||||||
null, // "i2l",
|
|
||||||
null, // "i2f",
|
|
||||||
null, // "i2d",
|
|
||||||
null, // "l2i",
|
|
||||||
null, // "l2f",
|
|
||||||
null, // "l2d",
|
|
||||||
null, // "f2i",
|
|
||||||
null, // "f2l",
|
|
||||||
null, // "f2d",
|
|
||||||
null, // "d2i",
|
|
||||||
null, // "d2l",
|
|
||||||
null, // "d2f",
|
|
||||||
null, // "i2b",
|
|
||||||
null, // "i2c",
|
|
||||||
null, // "i2s",
|
|
||||||
null, // "lcmp",
|
|
||||||
null, // "fcmpl",
|
|
||||||
null, // "fcmpg",
|
|
||||||
null, // "dcmpl",
|
|
||||||
null, // "dcmpg",
|
|
||||||
null, // "ifeq",
|
|
||||||
null, // "ifne",
|
|
||||||
null, // "iflt",
|
|
||||||
null, // "ifge",
|
|
||||||
null, // "ifgt",
|
|
||||||
null, // "ifle",
|
|
||||||
null, // "if_icmpeq",
|
|
||||||
null, // "if_icmpne",
|
|
||||||
null, // "if_icmplt",
|
|
||||||
null, // "if_icmpge",
|
|
||||||
null, // "if_icmpgt",
|
|
||||||
null, // "if_icmple",
|
|
||||||
null, // "if_acmpeq",
|
|
||||||
null, // "if_acmpne",
|
|
||||||
GOTO.class, // "goto",
|
|
||||||
JSR.class, // "jsr",
|
|
||||||
RET.class, // "ret",
|
|
||||||
TABLESWITCH.class, // "tableswitch",
|
|
||||||
LOOKUPSWITCH.class, // "lookupswitch",
|
|
||||||
null, // "ireturn",
|
|
||||||
null, // "lreturn",
|
|
||||||
null, // "freturn",
|
|
||||||
null, // "dreturn",
|
|
||||||
null, // "areturn",
|
|
||||||
null, // "return",
|
|
||||||
GETSTATIC.class, // "getstatic",
|
|
||||||
PUTSTATIC.class, // "putstatic",
|
|
||||||
GETFIELD.class, // "getfield",
|
|
||||||
PUTFIELD.class, // "putfield",
|
|
||||||
INVOKEVIRTUAL.class, // "invokevirtual",
|
|
||||||
INVOKESPECIAL.class, // "invokespecial",
|
|
||||||
INVOKESTATIC.class, // "invokestatic",
|
|
||||||
INVOKEINTERFACE.class, // "invokeinterface",
|
|
||||||
INVOKEDYNAMIC.class, // "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
|
|
||||||
NEW.class, // "new",
|
|
||||||
NEWARRAY.class, // "newarray",
|
|
||||||
ANEWARRAY.class, // "anewarray",
|
|
||||||
null, // "arraylength",
|
|
||||||
null, // "athrow",
|
|
||||||
CHECKCAST.class, // "checkcast",
|
|
||||||
INSTANCEOF.class, // "instanceof",
|
|
||||||
null, // "monitorenter",
|
|
||||||
null, // "monitorexit",
|
|
||||||
null, // "wide",
|
|
||||||
MULTIANEWARRAY.class, // "multianewarray",
|
|
||||||
null, // "ifnull",
|
|
||||||
null, // "ifnonnull",
|
|
||||||
GOTO_W.class, // "goto_w",
|
|
||||||
JSR_W.class // "jsr_w"
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,27 +1,9 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ExceptionHandler {
|
public class ExceptionHandler {
|
||||||
|
|
||||||
public int from = 0;
|
public int from = 0;
|
||||||
public int to = 0;
|
public int to = 0;
|
||||||
public int handler = 0;
|
public int handler = 0;
|
||||||
@ -30,32 +12,12 @@ public class ExceptionHandler {
|
|||||||
public int to_instr = 0;
|
public int to_instr = 0;
|
||||||
public int handler_instr = 0;
|
public int handler_instr = 0;
|
||||||
|
|
||||||
public int class_index = 0;
|
|
||||||
public String exceptionClass = null;
|
public String exceptionClass = null;
|
||||||
|
|
||||||
public ExceptionHandler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExceptionHandler(int from_raw, int to_raw, int handler_raw, String exceptionClass) {
|
|
||||||
this.from = from_raw;
|
|
||||||
this.to = to_raw;
|
|
||||||
this.handler = handler_raw;
|
|
||||||
this.exceptionClass = exceptionClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out) throws IOException {
|
|
||||||
out.writeShort(from);
|
|
||||||
out.writeShort(to);
|
|
||||||
out.writeShort(handler);
|
|
||||||
out.writeShort(class_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||||
|
|
||||||
return "from: " + from + " to: " + to + " handler: " + handler + new_line_separator +
|
return "from: " + from + " to: " + to + " handler: " + handler + new_line_separator +
|
||||||
"from_instr: " + from_instr + " to_instr: " + to_instr + " handler_instr: " + handler_instr + new_line_separator +
|
"from_instr: " + from_instr + " to_instr: " + to_instr + " handler_instr: " + handler_instr + new_line_separator +
|
||||||
"exceptionClass: " + exceptionClass + new_line_separator;
|
"exceptionClass: " + exceptionClass + new_line_separator;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,58 +1,19 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.interpreter.Util;
|
import java.util.Collections;
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ExceptionTable {
|
public class ExceptionTable {
|
||||||
|
public static final ExceptionTable EMPTY = new ExceptionTable(Collections.emptyList());
|
||||||
|
|
||||||
private List<ExceptionHandler> handlers = new ArrayList<ExceptionHandler>();
|
private final List<ExceptionHandler> handlers;
|
||||||
|
|
||||||
public ExceptionTable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExceptionTable(List<ExceptionHandler> handlers) {
|
public ExceptionTable(List<ExceptionHandler> handlers) {
|
||||||
this.handlers = handlers;
|
this.handlers = handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ExceptionHandler getHandlerByClass(StructContext context, int line, String valclass, boolean withany) {
|
|
||||||
|
|
||||||
ExceptionHandler res = null; // no handler found
|
|
||||||
|
|
||||||
for (ExceptionHandler handler : handlers) {
|
|
||||||
if (handler.from <= line && handler.to > line) {
|
|
||||||
String name = handler.exceptionClass;
|
|
||||||
|
|
||||||
if ((withany && name == null) || // any -> finally or synchronized handler
|
|
||||||
(name != null && Util.instanceOf(context, valclass, name))) {
|
|
||||||
res = handler;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ExceptionHandler> getHandlers() {
|
public List<ExceptionHandler> getHandlers() {
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||||
@ -25,7 +11,7 @@ public class FullInstructionSequence extends InstructionSequence {
|
|||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
|
public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
|
||||||
this.collinstr = collinstr;
|
super(collinstr);
|
||||||
this.exceptionTable = extable;
|
this.exceptionTable = extable;
|
||||||
|
|
||||||
// translate raw exception handlers to instr
|
// translate raw exception handlers to instr
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* opc_ifeq, opc_ifne, opc_iflt, opc_ifge, opc_ifgt, opc_ifle, opc_if_icmpeq, opc_if_icmpne, opc_if_icmplt,
|
|
||||||
* opc_if_icmpge, opc_if_icmpgt, opc_if_icmple, opc_if_acmpeq, opc_if_acmpne, opc_ifnull, opc_ifnonnull
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class IfInstruction extends JumpInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opcode);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +1,87 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class Instruction implements CodeConstants {
|
public class Instruction implements CodeConstants {
|
||||||
|
public static Instruction create(int opcode, boolean wide, int group, int bytecodeVersion, int[] operands) {
|
||||||
// *****************************************************************************
|
if (opcode >= opc_ifeq && opcode <= opc_if_acmpne ||
|
||||||
// public fields
|
opcode == opc_ifnull || opcode == opc_ifnonnull ||
|
||||||
// *****************************************************************************
|
opcode == opc_jsr || opcode == opc_jsr_w ||
|
||||||
|
opcode == opc_goto || opcode == opc_goto_w) {
|
||||||
public int opcode;
|
return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands);
|
||||||
|
}
|
||||||
public int group = CodeConstants.GROUP_GENERAL;
|
else if (opcode == opc_tableswitch || opcode == opc_lookupswitch) {
|
||||||
|
return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands);
|
||||||
public boolean wide = false;
|
}
|
||||||
|
else {
|
||||||
public int bytecode_version = BYTECODE_JAVA_LE_4;
|
return new Instruction(opcode, group, wide, bytecodeVersion, operands);
|
||||||
|
}
|
||||||
// *****************************************************************************
|
|
||||||
// private fields
|
|
||||||
// *****************************************************************************
|
|
||||||
|
|
||||||
private int[] operands = null;
|
|
||||||
|
|
||||||
// *****************************************************************************
|
|
||||||
// public methods
|
|
||||||
// *****************************************************************************
|
|
||||||
|
|
||||||
public Instruction() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int length() {
|
public static boolean equals(Instruction i1, Instruction i2) {
|
||||||
return 1;
|
return i1 != null && i2 != null &&
|
||||||
|
(i1 == i2 ||
|
||||||
|
i1.opcode == i2.opcode &&
|
||||||
|
i1.wide == i2.wide &&
|
||||||
|
i1.operandsCount() == i2.operandsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final int opcode;
|
||||||
|
public final int group;
|
||||||
|
public final boolean wide;
|
||||||
|
public final int bytecodeVersion;
|
||||||
|
|
||||||
|
protected final int[] operands;
|
||||||
|
|
||||||
|
public Instruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
|
||||||
|
this.opcode = opcode;
|
||||||
|
this.group = group;
|
||||||
|
this.wide = wide;
|
||||||
|
this.bytecodeVersion = bytecodeVersion;
|
||||||
|
this.operands = operands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initInstruction(InstructionSequence seq) { }
|
||||||
|
|
||||||
public int operandsCount() {
|
public int operandsCount() {
|
||||||
return (operands == null) ? 0 : operands.length;
|
return operands == null ? 0 : operands.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOperand(int index) {
|
public int operand(int index) {
|
||||||
return operands[index];
|
return operands[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction clone() {
|
public boolean canFallThrough() {
|
||||||
return ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, operands == null ? null : operands.clone());
|
return opcode != opc_goto && opcode != opc_goto_w && opcode != opc_ret &&
|
||||||
|
!(opcode >= opc_ireturn && opcode <= opc_return) &&
|
||||||
|
opcode != opc_athrow &&
|
||||||
|
opcode != opc_jsr && opcode != opc_tableswitch && opcode != opc_lookupswitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
String res = wide ? "@wide " : "";
|
if (wide) res.append("@wide ");
|
||||||
res += "@" + ConstantsUtil.getName(opcode);
|
res.append("@").append(TextUtil.getInstructionName(opcode));
|
||||||
|
|
||||||
int len = operandsCount();
|
int len = operandsCount();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
int op = operands[i];
|
int op = operands[i];
|
||||||
if (op < 0) {
|
if (op < 0) {
|
||||||
res += " -" + Integer.toHexString(-op);
|
res.append(" -").append(Integer.toHexString(-op));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res += " " + Integer.toHexString(op);
|
res.append(" ").append(Integer.toHexString(op));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canFallthrough() {
|
@Override
|
||||||
return opcode != opc_goto && opcode != opc_goto_w && opcode != opc_ret &&
|
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||||
!(opcode >= opc_ireturn && opcode <= opc_return) && opcode != opc_athrow
|
public Instruction clone() {
|
||||||
&& opcode != opc_jsr && opcode != opc_tableswitch && opcode != opc_lookupswitch;
|
return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public boolean equalsInstruction(Instruction instr) {
|
|
||||||
if (opcode != instr.opcode || wide != instr.wide
|
|
||||||
|| operandsCount() != instr.operandsCount()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operands != null) {
|
|
||||||
for (int i = 0; i < operands.length; i++) {
|
|
||||||
if (operands[i] != instr.getOperand(i)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// should be overwritten by subclasses
|
|
||||||
public void initInstruction(InstructionSequence seq) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// should be overwritten by subclasses
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// *****************************************************************************
|
|
||||||
// getter and setter methods
|
|
||||||
// *****************************************************************************
|
|
||||||
|
|
||||||
public int[] getOperands() {
|
|
||||||
return operands;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOperands(int[] operands) {
|
|
||||||
this.operands = operands;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +1,36 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.interpreter.Util;
|
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
|
||||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class InstructionSequence {
|
public abstract class InstructionSequence {
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// private fields
|
// private fields
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
protected VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
|
protected final VBStyleCollection<Instruction, Integer> collinstr;
|
||||||
|
|
||||||
protected int pointer = 0;
|
protected int pointer = 0;
|
||||||
|
|
||||||
protected ExceptionTable exceptionTable = new ExceptionTable();
|
protected ExceptionTable exceptionTable = ExceptionTable.EMPTY;
|
||||||
|
|
||||||
|
protected InstructionSequence() {
|
||||||
|
this(new VBStyleCollection<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
|
||||||
|
this.collinstr = collinstr;
|
||||||
|
}
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// public methods
|
// public methods
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
// to nbe overwritten
|
// to nbe overwritten
|
||||||
|
@Override
|
||||||
public InstructionSequence clone() {
|
public InstructionSequence clone() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -52,7 +38,7 @@ public abstract class InstructionSequence {
|
|||||||
public void clear() {
|
public void clear() {
|
||||||
collinstr.clear();
|
collinstr.clear();
|
||||||
pointer = 0;
|
pointer = 0;
|
||||||
exceptionTable = new ExceptionTable();
|
exceptionTable = ExceptionTable.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInstruction(Instruction inst, int offset) {
|
public void addInstruction(Instruction inst, int offset) {
|
||||||
@ -73,8 +59,10 @@ public abstract class InstructionSequence {
|
|||||||
collinstr.remove(index);
|
collinstr.remove(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction getCurrentInstr() {
|
public void removeLast() {
|
||||||
return collinstr.get(pointer);
|
if (!collinstr.isEmpty()) {
|
||||||
|
collinstr.remove(collinstr.size() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction getInstr(int index) {
|
public Instruction getInstr(int index) {
|
||||||
@ -85,16 +73,12 @@ public abstract class InstructionSequence {
|
|||||||
return collinstr.getLast();
|
return collinstr.getLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentOffset() {
|
public int getOffset(int index) {
|
||||||
return collinstr.getKey(pointer).intValue();
|
return collinstr.getKey(index);
|
||||||
}
|
|
||||||
|
|
||||||
public int getOffset(int index) {
|
|
||||||
return collinstr.getKey(index).intValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPointerByAbsOffset(int offset) {
|
public int getPointerByAbsOffset(int offset) {
|
||||||
Integer absoffset = new Integer(offset);
|
Integer absoffset = offset;
|
||||||
if (collinstr.containsKey(absoffset)) {
|
if (collinstr.containsKey(absoffset)) {
|
||||||
return collinstr.getIndexByKey(absoffset);
|
return collinstr.getIndexByKey(absoffset);
|
||||||
}
|
}
|
||||||
@ -104,7 +88,7 @@ public int getOffset(int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getPointerByRelOffset(int offset) {
|
public int getPointerByRelOffset(int offset) {
|
||||||
Integer absoffset = new Integer(collinstr.getKey(pointer).intValue() + offset);
|
Integer absoffset = collinstr.getKey(pointer) + offset;
|
||||||
if (collinstr.containsKey(absoffset)) {
|
if (collinstr.containsKey(absoffset)) {
|
||||||
return collinstr.getIndexByKey(absoffset);
|
return collinstr.getIndexByKey(absoffset);
|
||||||
}
|
}
|
||||||
@ -113,13 +97,6 @@ public int getOffset(int index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPointerByAbsOffset(int offset) {
|
|
||||||
Integer absoffset = new Integer(collinstr.getKey(pointer).intValue() + offset);
|
|
||||||
if (collinstr.containsKey(absoffset)) {
|
|
||||||
pointer = collinstr.getIndexByKey(absoffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
public int length() {
|
||||||
return collinstr.size();
|
return collinstr.size();
|
||||||
}
|
}
|
||||||
@ -143,7 +120,7 @@ public int getOffset(int index) {
|
|||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < collinstr.size(); i++) {
|
for (int i = 0; i < collinstr.size(); i++) {
|
||||||
buf.append(InterpreterUtil.getIndentString(indent));
|
buf.append(TextUtil.getIndentString(indent));
|
||||||
buf.append(collinstr.getKey(i).intValue());
|
buf.append(collinstr.getKey(i).intValue());
|
||||||
buf.append(": ");
|
buf.append(": ");
|
||||||
buf.append(collinstr.get(i).toString());
|
buf.append(collinstr.get(i).toString());
|
||||||
@ -153,58 +130,6 @@ public int getOffset(int index) {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeCodeToStream(DataOutputStream out) throws IOException {
|
|
||||||
|
|
||||||
for (int i = 0; i < collinstr.size(); i++) {
|
|
||||||
collinstr.get(i).writeToStream(out, collinstr.getKey(i).intValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeExceptionsToStream(DataOutputStream out) throws IOException {
|
|
||||||
|
|
||||||
List<ExceptionHandler> handlers = exceptionTable.getHandlers();
|
|
||||||
|
|
||||||
out.writeShort(handlers.size());
|
|
||||||
for (int i = 0; i < handlers.size(); i++) {
|
|
||||||
handlers.get(i).writeToStream(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sortHandlers(final StructContext context) {
|
|
||||||
|
|
||||||
Collections.sort(exceptionTable.getHandlers(), new Comparator<ExceptionHandler>() {
|
|
||||||
|
|
||||||
public int compare(ExceptionHandler handler0, ExceptionHandler handler1) {
|
|
||||||
|
|
||||||
if (handler0.to == handler1.to) {
|
|
||||||
if (handler0.exceptionClass == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (handler1.exceptionClass == null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (handler0.exceptionClass.equals(handler1.exceptionClass)) {
|
|
||||||
return (handler0.from > handler1.from) ? -1 : 1; // invalid code
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (Util.instanceOf(context, handler0.exceptionClass, handler1.exceptionClass)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (handler0.to > handler1.to) ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// getter and setter methods
|
// getter and setter methods
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
@ -220,8 +145,4 @@ public int getOffset(int index) {
|
|||||||
public ExceptionTable getExceptionTable() {
|
public ExceptionTable getExceptionTable() {
|
||||||
return exceptionTable;
|
return exceptionTable;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void setExceptionTable(ExceptionTable exceptionTable) {
|
|
||||||
this.exceptionTable = exceptionTable;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +1,22 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
/*
|
|
||||||
* opc_ifeq, opc_ifne, opc_iflt, opc_ifge, opc_ifgt, opc_ifle, opc_if_icmpeq, opc_if_icmpne, opc_if_icmplt,
|
|
||||||
* opc_if_icmpge, opc_if_icmpgt, opc_if_icmple, opc_if_acmpeq, opc_if_acmpne, opc_ifnull, opc_ifnonnull
|
|
||||||
* opc_goto, opc_jsr, opc_goto_w, opc_jsr_w
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public class JumpInstruction extends Instruction {
|
public class JumpInstruction extends Instruction {
|
||||||
|
|
||||||
public int destination;
|
public int destination;
|
||||||
|
|
||||||
public JumpInstruction() {
|
public JumpInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
|
||||||
|
super(opcode, group, wide, bytecodeVersion, operands);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void initInstruction(InstructionSequence seq) {
|
public void initInstruction(InstructionSequence seq) {
|
||||||
destination = seq.getPointerByRelOffset(this.getOperand(0));
|
destination = seq.getPointerByRelOffset(this.operand(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public JumpInstruction clone() {
|
public JumpInstruction clone() {
|
||||||
JumpInstruction newinstr = (JumpInstruction)super.clone();
|
JumpInstruction copy = (JumpInstruction)super.clone();
|
||||||
|
copy.destination = destination;
|
||||||
newinstr.destination = destination;
|
return copy;
|
||||||
return newinstr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||||
@ -23,17 +9,14 @@ public class SimpleInstructionSequence extends InstructionSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SimpleInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
|
public SimpleInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
|
||||||
this.collinstr = collinstr;
|
super(collinstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SimpleInstructionSequence clone() {
|
public SimpleInstructionSequence clone() {
|
||||||
SimpleInstructionSequence newseq = new SimpleInstructionSequence(collinstr.clone());
|
SimpleInstructionSequence newseq = new SimpleInstructionSequence(collinstr.clone());
|
||||||
newseq.setPointer(this.getPointer());
|
newseq.setPointer(this.getPointer());
|
||||||
|
|
||||||
return newseq;
|
return newseq;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeInstruction(int index) {
|
|
||||||
collinstr.remove(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,97 +1,61 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code;
|
package org.jetbrains.java.decompiler.code;
|
||||||
|
|
||||||
/*
|
|
||||||
* opc_tableswitch, lookupswitch
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class SwitchInstruction extends Instruction {
|
public class SwitchInstruction extends Instruction {
|
||||||
|
|
||||||
private int[] destinations;
|
private int[] destinations;
|
||||||
|
|
||||||
private int[] values;
|
private int[] values;
|
||||||
|
private int defaultDestination;
|
||||||
|
|
||||||
private int defaultdest;
|
public SwitchInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
|
||||||
|
super(opcode, group, wide, bytecodeVersion, operands);
|
||||||
public SwitchInstruction() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void initInstruction(InstructionSequence seq) {
|
public void initInstruction(InstructionSequence seq) {
|
||||||
|
defaultDestination = seq.getPointerByRelOffset(operands[0]);
|
||||||
|
|
||||||
int pref = (opcode == CodeConstants.opc_tableswitch ? 3 : 2);
|
int prefix = opcode == CodeConstants.opc_tableswitch ? 3 : 2;
|
||||||
int len = this.getOperands().length - pref;
|
int len = operands.length - prefix;
|
||||||
defaultdest = seq.getPointerByRelOffset(this.getOperand(0));
|
|
||||||
|
|
||||||
int low = 0;
|
int low = 0;
|
||||||
|
|
||||||
if (opcode == CodeConstants.opc_lookupswitch) {
|
if (opcode == CodeConstants.opc_lookupswitch) {
|
||||||
len /= 2;
|
len /= 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
low = this.getOperand(1);
|
low = operands[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
destinations = new int[len];
|
destinations = new int[len];
|
||||||
values = new int[len];
|
values = new int[len];
|
||||||
|
|
||||||
for (int i = 0, k = 0; i < len; i++, k++) {
|
for (int i = 0, k = 0; i < len; i++, k++) {
|
||||||
if (opcode == CodeConstants.opc_lookupswitch) {
|
if (opcode == CodeConstants.opc_lookupswitch) {
|
||||||
values[i] = this.getOperand(pref + k);
|
values[i] = operands[prefix + k];
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
values[i] = low + k;
|
values[i] = low + k;
|
||||||
}
|
}
|
||||||
destinations[i] = seq.getPointerByRelOffset(this.getOperand(pref + k));
|
destinations[i] = seq.getPointerByRelOffset(operands[prefix + k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwitchInstruction clone() {
|
|
||||||
SwitchInstruction newinstr = (SwitchInstruction)super.clone();
|
|
||||||
|
|
||||||
newinstr.defaultdest = defaultdest;
|
|
||||||
newinstr.destinations = destinations.clone();
|
|
||||||
newinstr.values = values.clone();
|
|
||||||
|
|
||||||
return newinstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getDestinations() {
|
public int[] getDestinations() {
|
||||||
return destinations;
|
return destinations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDestinations(int[] destinations) {
|
|
||||||
this.destinations = destinations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDefaultdest() {
|
|
||||||
return defaultdest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultdest(int defaultdest) {
|
|
||||||
this.defaultdest = defaultdest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getValues() {
|
public int[] getValues() {
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValues(int[] values) {
|
public int getDefaultDestination() {
|
||||||
this.values = values;
|
return defaultDestination;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public SwitchInstruction clone() {
|
||||||
|
SwitchInstruction copy = (SwitchInstruction)super.clone();
|
||||||
|
copy.defaultDestination = defaultDestination;
|
||||||
|
copy.destinations = destinations.clone();
|
||||||
|
copy.values = values.clone();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.cfg;
|
package org.jetbrains.java.decompiler.code.cfg;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
import org.jetbrains.java.decompiler.code.Instruction;
|
||||||
@ -30,8 +16,7 @@ public class BasicBlock implements IGraphNode {
|
|||||||
// public fields
|
// public fields
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
public int id = 0;
|
public int id;
|
||||||
|
|
||||||
public int mark = 0;
|
public int mark = 0;
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
@ -40,19 +25,11 @@ public class BasicBlock implements IGraphNode {
|
|||||||
|
|
||||||
private InstructionSequence seq = new SimpleInstructionSequence();
|
private InstructionSequence seq = new SimpleInstructionSequence();
|
||||||
|
|
||||||
private List<BasicBlock> preds = new ArrayList<BasicBlock>();
|
private final List<BasicBlock> preds = new ArrayList<>();
|
||||||
|
private final List<BasicBlock> succs = new ArrayList<>();
|
||||||
private List<BasicBlock> succs = new ArrayList<BasicBlock>();
|
private final List<Integer> instrOldOffsets = new ArrayList<>();
|
||||||
|
private final List<BasicBlock> predExceptions = new ArrayList<>();
|
||||||
private List<Integer> instrOldOffsets = new ArrayList<Integer>();
|
private final List<BasicBlock> succExceptions = new ArrayList<>();
|
||||||
|
|
||||||
private List<BasicBlock> predExceptions = new ArrayList<BasicBlock>();
|
|
||||||
|
|
||||||
private List<BasicBlock> succExceptions = new ArrayList<BasicBlock>();
|
|
||||||
|
|
||||||
|
|
||||||
public BasicBlock() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicBlock(int id) {
|
public BasicBlock(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -62,24 +39,17 @@ public class BasicBlock implements IGraphNode {
|
|||||||
// public methods
|
// public methods
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
public Object clone() {
|
@Override
|
||||||
|
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||||
|
public BasicBlock clone() {
|
||||||
|
BasicBlock block = new BasicBlock(id);
|
||||||
|
|
||||||
BasicBlock block = new BasicBlock();
|
|
||||||
block.id = id;
|
|
||||||
block.setSeq(seq.clone());
|
block.setSeq(seq.clone());
|
||||||
block.setInstrOldOffsets(new ArrayList<Integer>(instrOldOffsets));
|
block.instrOldOffsets.addAll(instrOldOffsets);
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void free() {
|
|
||||||
preds.clear();
|
|
||||||
succs.clear();
|
|
||||||
instrOldOffsets.clear();
|
|
||||||
succExceptions.clear();
|
|
||||||
seq = new SimpleInstructionSequence();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instruction getInstruction(int index) {
|
public Instruction getInstruction(int index) {
|
||||||
return seq.getInstr(index);
|
return seq.getInstr(index);
|
||||||
}
|
}
|
||||||
@ -110,7 +80,7 @@ public class BasicBlock implements IGraphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removePredecessor(BasicBlock block) {
|
public void removePredecessor(BasicBlock block) {
|
||||||
while (preds.remove(block)) ;
|
while (preds.remove(block)) /**/;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSuccessor(BasicBlock block) {
|
public void addSuccessor(BasicBlock block) {
|
||||||
@ -119,11 +89,11 @@ public class BasicBlock implements IGraphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeSuccessor(BasicBlock block) {
|
public void removeSuccessor(BasicBlock block) {
|
||||||
while (succs.remove(block)) ;
|
while (succs.remove(block)) /**/;
|
||||||
block.removePredecessor(this);
|
block.removePredecessor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: unify block comparisons: id or direkt equality
|
// FIXME: unify block comparisons: id or direct equality
|
||||||
public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) {
|
public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) {
|
||||||
for (int i = 0; i < succs.size(); i++) {
|
for (int i = 0; i < succs.size(); i++) {
|
||||||
if (succs.get(i).id == oldBlock.id) {
|
if (succs.get(i).id == oldBlock.id) {
|
||||||
@ -147,7 +117,7 @@ public class BasicBlock implements IGraphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removePredecessorException(BasicBlock block) {
|
public void removePredecessorException(BasicBlock block) {
|
||||||
while (predExceptions.remove(block)) ;
|
while (predExceptions.remove(block)) /**/;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSuccessorException(BasicBlock block) {
|
public void addSuccessorException(BasicBlock block) {
|
||||||
@ -158,7 +128,7 @@ public class BasicBlock implements IGraphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeSuccessorException(BasicBlock block) {
|
public void removeSuccessorException(BasicBlock block) {
|
||||||
while (succExceptions.remove(block)) ;
|
while (succExceptions.remove(block)) /**/;
|
||||||
block.removePredecessorException(this);
|
block.removePredecessorException(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,27 +143,6 @@ public class BasicBlock implements IGraphNode {
|
|||||||
return id + ":" + new_line_separator + seq.toString(indent);
|
return id + ":" + new_line_separator + seq.toString(indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toStringOldIndices() {
|
|
||||||
|
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
|
|
||||||
for (int i = 0; i < seq.length(); i++) {
|
|
||||||
if (i < instrOldOffsets.size()) {
|
|
||||||
buf.append(instrOldOffsets.get(i));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buf.append("-1");
|
|
||||||
}
|
|
||||||
buf.append(": ");
|
|
||||||
buf.append(seq.getInstr(i).toString());
|
|
||||||
buf.append(new_line_separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccessor(BasicBlock block) {
|
public boolean isSuccessor(BasicBlock block) {
|
||||||
for (BasicBlock succ : succs) {
|
for (BasicBlock succ : succs) {
|
||||||
if (succ.id == block.id) {
|
if (succ.id == block.id) {
|
||||||
@ -203,15 +152,6 @@ public class BasicBlock implements IGraphNode {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPredecessor(BasicBlock block) {
|
|
||||||
for (int i = 0; i < preds.size(); i++) {
|
|
||||||
if (preds.get(i).id == block.id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// getter and setter methods
|
// getter and setter methods
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
@ -220,12 +160,9 @@ public class BasicBlock implements IGraphNode {
|
|||||||
return instrOldOffsets;
|
return instrOldOffsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInstrOldOffsets(List<Integer> instrInds) {
|
@Override
|
||||||
this.instrOldOffsets = instrInds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<? extends IGraphNode> getPredecessors() {
|
public List<? extends IGraphNode> getPredecessors() {
|
||||||
List<BasicBlock> lst = new ArrayList<BasicBlock>(preds);
|
List<BasicBlock> lst = new ArrayList<>(preds);
|
||||||
lst.addAll(predExceptions);
|
lst.addAll(predExceptions);
|
||||||
return lst;
|
return lst;
|
||||||
}
|
}
|
||||||
@ -234,10 +171,6 @@ public class BasicBlock implements IGraphNode {
|
|||||||
return preds;
|
return preds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreds(List<BasicBlock> preds) {
|
|
||||||
this.preds = preds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InstructionSequence getSeq() {
|
public InstructionSequence getSeq() {
|
||||||
return seq;
|
return seq;
|
||||||
}
|
}
|
||||||
@ -250,25 +183,11 @@ public class BasicBlock implements IGraphNode {
|
|||||||
return succs;
|
return succs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSuccs(List<BasicBlock> succs) {
|
|
||||||
this.succs = succs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public List<BasicBlock> getSuccExceptions() {
|
public List<BasicBlock> getSuccExceptions() {
|
||||||
return succExceptions;
|
return succExceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setSuccExceptions(List<BasicBlock> succExceptions) {
|
|
||||||
this.succExceptions = succExceptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<BasicBlock> getPredExceptions() {
|
public List<BasicBlock> getPredExceptions() {
|
||||||
return predExceptions;
|
return predExceptions;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void setPredExceptions(List<BasicBlock> predExceptions) {
|
|
||||||
this.predExceptions = predExceptions;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +1,11 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.cfg;
|
package org.jetbrains.java.decompiler.code.cfg;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.*;
|
import org.jetbrains.java.decompiler.code.*;
|
||||||
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
|
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
|
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
|
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
|
||||||
@ -47,7 +34,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
private Map<BasicBlock, BasicBlock> subroutines;
|
private Map<BasicBlock, BasicBlock> subroutines;
|
||||||
|
|
||||||
private Set<BasicBlock> finallyExits = new HashSet<BasicBlock>();
|
private final Set<BasicBlock> finallyExits = new HashSet<>();
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// constructors
|
// constructors
|
||||||
@ -62,19 +49,6 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
// public methods
|
// public methods
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
public void free() {
|
|
||||||
|
|
||||||
for (BasicBlock block : blocks) {
|
|
||||||
block.free();
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks.clear();
|
|
||||||
first = null;
|
|
||||||
last = null;
|
|
||||||
exceptions.clear();
|
|
||||||
finallyExits.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeMarkers() {
|
public void removeMarkers() {
|
||||||
for (BasicBlock block : blocks) {
|
for (BasicBlock block : blocks) {
|
||||||
block.mark = 0;
|
block.mark = 0;
|
||||||
@ -82,6 +56,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
if (blocks == null) return "Empty";
|
||||||
|
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||||
|
|
||||||
@ -93,12 +68,11 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
buf.append("----- Edges -----").append(new_line_separator);
|
buf.append("----- Edges -----").append(new_line_separator);
|
||||||
|
|
||||||
List<BasicBlock> suc = block.getSuccs();
|
List<BasicBlock> suc = block.getSuccs();
|
||||||
for (int j = 0; j < suc.size(); j++) {
|
for (BasicBlock aSuc : suc) {
|
||||||
buf.append(">>>>>>>>(regular) Block ").append(suc.get(j).id).append(new_line_separator);
|
buf.append(">>>>>>>>(regular) Block ").append(aSuc.id).append(new_line_separator);
|
||||||
}
|
}
|
||||||
suc = block.getSuccExceptions();
|
suc = block.getSuccExceptions();
|
||||||
for (int j = 0; j < suc.size(); j++) {
|
for (BasicBlock handler : suc) {
|
||||||
BasicBlock handler = suc.get(j);
|
|
||||||
ExceptionRangeCFG range = getExceptionRange(handler, block);
|
ExceptionRangeCFG range = getExceptionRange(handler, block);
|
||||||
|
|
||||||
if (range == null) {
|
if (range == null) {
|
||||||
@ -123,9 +97,9 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void inlineJsr(StructMethod mt) {
|
public void inlineJsr(StructClass cl, StructMethod mt) {
|
||||||
processJsr();
|
processJsr();
|
||||||
removeJsr(mt);
|
removeJsr(cl, mt);
|
||||||
|
|
||||||
removeMarkers();
|
removeMarkers();
|
||||||
|
|
||||||
@ -169,13 +143,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Entry<BasicBlock, BasicBlock>> it = subroutines.entrySet().iterator();
|
subroutines.entrySet().removeIf(ent -> ent.getKey() == block || ent.getValue() == block);
|
||||||
while (it.hasNext()) {
|
|
||||||
Entry<BasicBlock, BasicBlock> ent = it.next();
|
|
||||||
if (ent.getKey() == block || ent.getValue() == block) {
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) {
|
public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) {
|
||||||
@ -224,7 +192,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
short[] states = findStartInstructions(instrseq);
|
short[] states = findStartInstructions(instrseq);
|
||||||
|
|
||||||
Map<Integer, BasicBlock> mapInstrBlocks = new HashMap<Integer, BasicBlock>();
|
Map<Integer, BasicBlock> mapInstrBlocks = new HashMap<>();
|
||||||
VBStyleCollection<BasicBlock, Integer> colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks);
|
VBStyleCollection<BasicBlock, Integer> colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks);
|
||||||
|
|
||||||
blocks = colBlocks;
|
blocks = colBlocks;
|
||||||
@ -243,7 +211,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
int len = seq.length();
|
int len = seq.length();
|
||||||
short[] inststates = new short[len];
|
short[] inststates = new short[len];
|
||||||
|
|
||||||
Set<Integer> excSet = new HashSet<Integer>();
|
Set<Integer> excSet = new HashSet<>();
|
||||||
|
|
||||||
for (ExceptionHandler handler : seq.getExceptionTable().getHandlers()) {
|
for (ExceptionHandler handler : seq.getExceptionTable().getHandlers()) {
|
||||||
excSet.add(handler.from_instr);
|
excSet.add(handler.from_instr);
|
||||||
@ -255,7 +223,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
|
||||||
// exception blocks
|
// exception blocks
|
||||||
if (excSet.contains(new Integer(i))) {
|
if (excSet.contains(i)) {
|
||||||
inststates[i] = 1;
|
inststates[i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +242,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
for (int j = dests.length - 1; j >= 0; j--) {
|
for (int j = dests.length - 1; j >= 0; j--) {
|
||||||
inststates[dests[j]] = 1;
|
inststates[dests[j]] = 1;
|
||||||
}
|
}
|
||||||
inststates[swinstr.getDefaultdest()] = 1;
|
inststates[swinstr.getDefaultDestination()] = 1;
|
||||||
if (i + 1 < len) {
|
if (i + 1 < len) {
|
||||||
inststates[i + 1] = 1;
|
inststates[i + 1] = 1;
|
||||||
}
|
}
|
||||||
@ -292,10 +260,10 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
InstructionSequence instrseq,
|
InstructionSequence instrseq,
|
||||||
Map<Integer, BasicBlock> mapInstrBlocks) {
|
Map<Integer, BasicBlock> mapInstrBlocks) {
|
||||||
|
|
||||||
VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<BasicBlock, Integer>();
|
VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<>();
|
||||||
|
|
||||||
InstructionSequence currseq = null;
|
InstructionSequence currseq = null;
|
||||||
ArrayList<Integer> lstOffs = null;
|
List<Integer> lstOffs = null;
|
||||||
|
|
||||||
int len = startblock.length;
|
int len = startblock.length;
|
||||||
short counter = 0;
|
short counter = 0;
|
||||||
@ -305,14 +273,11 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
|
||||||
if (startblock[i] == 1) {
|
if (startblock[i] == 1) {
|
||||||
currentBlock = new BasicBlock();
|
currentBlock = new BasicBlock(++counter);
|
||||||
currentBlock.id = ++counter;
|
|
||||||
|
|
||||||
currseq = new SimpleInstructionSequence();
|
currseq = currentBlock.getSeq();
|
||||||
lstOffs = new ArrayList<Integer>();
|
lstOffs = currentBlock.getInstrOldOffsets();
|
||||||
|
|
||||||
currentBlock.setSeq(currseq);
|
|
||||||
currentBlock.setInstrOldOffsets(lstOffs);
|
|
||||||
col.addWithKey(currentBlock, currentBlock.id);
|
col.addWithKey(currentBlock, currentBlock.id);
|
||||||
|
|
||||||
blockoffset = instrseq.getOffset(i);
|
blockoffset = instrseq.getOffset(i);
|
||||||
@ -338,7 +303,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
BasicBlock block = lstbb.get(i);
|
BasicBlock block = lstbb.get(i);
|
||||||
Instruction instr = block.getLastInstruction();
|
Instruction instr = block.getLastInstruction();
|
||||||
|
|
||||||
boolean fallthrough = instr.canFallthrough();
|
boolean fallthrough = instr.canFallThrough();
|
||||||
BasicBlock bTemp;
|
BasicBlock bTemp;
|
||||||
|
|
||||||
switch (instr.group) {
|
switch (instr.group) {
|
||||||
@ -352,10 +317,10 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
SwitchInstruction sinstr = (SwitchInstruction)instr;
|
SwitchInstruction sinstr = (SwitchInstruction)instr;
|
||||||
int[] dests = sinstr.getDestinations();
|
int[] dests = sinstr.getDestinations();
|
||||||
|
|
||||||
bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest());
|
bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultDestination());
|
||||||
block.addSuccessor(bTemp);
|
block.addSuccessor(bTemp);
|
||||||
for (int j = 0; j < dests.length; j++) {
|
for (int dest1 : dests) {
|
||||||
bTemp = mapInstrBlocks.get(dests[j]);
|
bTemp = mapInstrBlocks.get(dest1);
|
||||||
block.addSuccessor(bTemp);
|
block.addSuccessor(bTemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,9 +334,9 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
private void setExceptionEdges(InstructionSequence instrseq, Map<Integer, BasicBlock> instrBlocks) {
|
private void setExceptionEdges(InstructionSequence instrseq, Map<Integer, BasicBlock> instrBlocks) {
|
||||||
|
|
||||||
exceptions = new ArrayList<ExceptionRangeCFG>();
|
exceptions = new ArrayList<>();
|
||||||
|
|
||||||
Map<String, ExceptionRangeCFG> mapRanges = new HashMap<String, ExceptionRangeCFG>();
|
Map<String, ExceptionRangeCFG> mapRanges = new HashMap<>();
|
||||||
|
|
||||||
for (ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) {
|
for (ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) {
|
||||||
|
|
||||||
@ -387,7 +352,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
List<BasicBlock> protectedRange = new ArrayList<BasicBlock>();
|
List<BasicBlock> protectedRange = new ArrayList<>();
|
||||||
for (int j = from.id; j < to.id; j++) {
|
for (int j = from.id; j < to.id; j++) {
|
||||||
BasicBlock block = blocks.getWithKey(j);
|
BasicBlock block = blocks.getWithKey(j);
|
||||||
protectedRange.add(block);
|
protectedRange.add(block);
|
||||||
@ -396,7 +361,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null
|
ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null
|
||||||
? null
|
? null
|
||||||
: Arrays.asList(handler.exceptionClass));
|
: Collections.singletonList(handler.exceptionClass));
|
||||||
mapRanges.put(key, range);
|
mapRanges.put(key, range);
|
||||||
|
|
||||||
exceptions.add(range);
|
exceptions.add(range);
|
||||||
@ -406,19 +371,19 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
private void setSubroutineEdges() {
|
private void setSubroutineEdges() {
|
||||||
|
|
||||||
final Map<BasicBlock, BasicBlock> subroutines = new HashMap<BasicBlock, BasicBlock>();
|
final Map<BasicBlock, BasicBlock> subroutines = new LinkedHashMap<>();
|
||||||
|
|
||||||
for (BasicBlock block : blocks) {
|
for (BasicBlock block : blocks) {
|
||||||
|
|
||||||
if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) {
|
if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) {
|
||||||
|
|
||||||
LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
|
LinkedList<BasicBlock> stack = new LinkedList<>();
|
||||||
LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<LinkedList<BasicBlock>>();
|
LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<>();
|
||||||
|
|
||||||
Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
|
Set<BasicBlock> setVisited = new HashSet<>();
|
||||||
|
|
||||||
stack.add(block);
|
stack.add(block);
|
||||||
stackJsrStacks.add(new LinkedList<BasicBlock>());
|
stackJsrStacks.add(new LinkedList<>());
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
|
|
||||||
@ -451,7 +416,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
for (BasicBlock succ : node.getSuccs()) {
|
for (BasicBlock succ : node.getSuccs()) {
|
||||||
if (!setVisited.contains(succ)) {
|
if (!setVisited.contains(succ)) {
|
||||||
stack.add(succ);
|
stack.add(succ);
|
||||||
stackJsrStacks.add(new LinkedList<BasicBlock>(jsrstack));
|
stackJsrStacks.add(new LinkedList<>(jsrstack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,7 +433,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class JsrRecord {
|
private static final class JsrRecord {
|
||||||
private final BasicBlock jsr;
|
private final BasicBlock jsr;
|
||||||
private final Set<BasicBlock> range;
|
private final Set<BasicBlock> range;
|
||||||
private final BasicBlock ret;
|
private final BasicBlock ret;
|
||||||
@ -482,7 +447,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
private int processJsrRanges() {
|
private int processJsrRanges() {
|
||||||
|
|
||||||
List<JsrRecord> lstJsrAll = new ArrayList<JsrRecord>();
|
List<JsrRecord> lstJsrAll = new ArrayList<>();
|
||||||
|
|
||||||
// get all jsr ranges
|
// get all jsr ranges
|
||||||
for (Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()) {
|
for (Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()) {
|
||||||
@ -494,7 +459,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
// sort ranges
|
// sort ranges
|
||||||
// FIXME: better sort order
|
// FIXME: better sort order
|
||||||
List<JsrRecord> lstJsr = new ArrayList<JsrRecord>();
|
List<JsrRecord> lstJsr = new ArrayList<>();
|
||||||
for (JsrRecord arr : lstJsrAll) {
|
for (JsrRecord arr : lstJsrAll) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < lstJsr.size(); i++) {
|
for (; i < lstJsr.size(); i++) {
|
||||||
@ -516,7 +481,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
Set<BasicBlock> set1 = arr1.range;
|
Set<BasicBlock> set1 = arr1.range;
|
||||||
|
|
||||||
if (!set.contains(arr1.jsr) && !set1.contains(arr.jsr)) { // rang 0 doesn't contain entry 1 and vice versa
|
if (!set.contains(arr1.jsr) && !set1.contains(arr.jsr)) { // rang 0 doesn't contain entry 1 and vice versa
|
||||||
Set<BasicBlock> setc = new HashSet<BasicBlock>(set);
|
Set<BasicBlock> setc = new HashSet<>(set);
|
||||||
setc.retainAll(set1);
|
setc.retainAll(set1);
|
||||||
|
|
||||||
if (!setc.isEmpty()) {
|
if (!setc.isEmpty()) {
|
||||||
@ -532,9 +497,9 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
private Set<BasicBlock> getJsrRange(BasicBlock jsr, BasicBlock ret) {
|
private Set<BasicBlock> getJsrRange(BasicBlock jsr, BasicBlock ret) {
|
||||||
|
|
||||||
Set<BasicBlock> blocks = new HashSet<BasicBlock>();
|
Set<BasicBlock> blocks = new HashSet<>();
|
||||||
|
|
||||||
List<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
|
List<BasicBlock> lstNodes = new LinkedList<>();
|
||||||
lstNodes.add(jsr);
|
lstNodes.add(jsr);
|
||||||
|
|
||||||
BasicBlock dom = jsr.getSuccs().get(0);
|
BasicBlock dom = jsr.getSuccs().get(0);
|
||||||
@ -596,8 +561,8 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
private void splitJsrRange(BasicBlock jsr, BasicBlock ret, Set<BasicBlock> common_blocks) {
|
private void splitJsrRange(BasicBlock jsr, BasicBlock ret, Set<BasicBlock> common_blocks) {
|
||||||
|
|
||||||
List<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
|
List<BasicBlock> lstNodes = new LinkedList<>();
|
||||||
Map<Integer, BasicBlock> mapNewNodes = new HashMap<Integer, BasicBlock>();
|
Map<Integer, BasicBlock> mapNewNodes = new HashMap<>();
|
||||||
|
|
||||||
lstNodes.add(jsr);
|
lstNodes.add(jsr);
|
||||||
mapNewNodes.put(jsr.id, jsr);
|
mapNewNodes.put(jsr.id, jsr);
|
||||||
@ -633,9 +598,8 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
node.replaceSuccessor(child, mapNewNodes.get(childid));
|
node.replaceSuccessor(child, mapNewNodes.get(childid));
|
||||||
}
|
}
|
||||||
else if (common_blocks.contains(child)) {
|
else if (common_blocks.contains(child)) {
|
||||||
|
|
||||||
// make a copy of the current block
|
// make a copy of the current block
|
||||||
BasicBlock copy = (BasicBlock)child.clone();
|
BasicBlock copy = child.clone();
|
||||||
copy.id = ++last_id;
|
copy.id = ++last_id;
|
||||||
// copy all successors
|
// copy all successors
|
||||||
if (copy.getLastInstruction().opcode == CodeConstants.opc_ret &&
|
if (copy.getLastInstruction().opcode == CodeConstants.opc_ret &&
|
||||||
@ -682,14 +646,14 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
ExceptionRangeCFG range = exceptions.get(i);
|
ExceptionRangeCFG range = exceptions.get(i);
|
||||||
List<BasicBlock> lstRange = range.getProtectedRange();
|
List<BasicBlock> lstRange = range.getProtectedRange();
|
||||||
|
|
||||||
HashSet<BasicBlock> setBoth = new HashSet<BasicBlock>(common_blocks);
|
HashSet<BasicBlock> setBoth = new HashSet<>(common_blocks);
|
||||||
setBoth.retainAll(lstRange);
|
setBoth.retainAll(lstRange);
|
||||||
|
|
||||||
if (setBoth.size() > 0) {
|
if (setBoth.size() > 0) {
|
||||||
List<BasicBlock> lstNewRange;
|
List<BasicBlock> lstNewRange;
|
||||||
|
|
||||||
if (setBoth.size() == lstRange.size()) {
|
if (setBoth.size() == lstRange.size()) {
|
||||||
lstNewRange = new ArrayList<BasicBlock>();
|
lstNewRange = new ArrayList<>();
|
||||||
ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange,
|
ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange,
|
||||||
mapNewNodes.get(range.getHandler().id), range.getExceptionTypes());
|
mapNewNodes.get(range.getHandler().id), range.getExceptionTypes());
|
||||||
exceptions.add(newRange);
|
exceptions.add(newRange);
|
||||||
@ -705,8 +669,8 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeJsr(StructMethod mt) {
|
private void removeJsr(StructClass cl, StructMethod mt) {
|
||||||
removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
|
removeJsrInstructions(cl.getPool(), first, DataPoint.getInitialDataPoint(mt));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {
|
private static void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {
|
||||||
@ -753,7 +717,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
if (suc.mark != 1) {
|
if (suc.mark != 1) {
|
||||||
|
|
||||||
DataPoint point = new DataPoint();
|
DataPoint point = new DataPoint();
|
||||||
point.setLocalVariables(new ArrayList<VarType>(data.getLocalVariables()));
|
point.setLocalVariables(new ArrayList<>(data.getLocalVariables()));
|
||||||
point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
|
point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
|
||||||
|
|
||||||
removeJsrInstructions(pool, suc, point);
|
removeJsrInstructions(pool, suc, point);
|
||||||
@ -765,9 +729,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
first = blocks.get(0);
|
first = blocks.get(0);
|
||||||
|
|
||||||
last = new BasicBlock();
|
last = new BasicBlock(++last_id);
|
||||||
last.id = ++last_id;
|
|
||||||
last.setSeq(new SimpleInstructionSequence());
|
|
||||||
|
|
||||||
for (BasicBlock block : blocks) {
|
for (BasicBlock block : blocks) {
|
||||||
if (block.getSuccs().isEmpty()) {
|
if (block.getSuccs().isEmpty()) {
|
||||||
@ -778,18 +740,18 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
public List<BasicBlock> getReversePostOrder() {
|
public List<BasicBlock> getReversePostOrder() {
|
||||||
|
|
||||||
List<BasicBlock> res = new LinkedList<BasicBlock>();
|
List<BasicBlock> res = new LinkedList<>();
|
||||||
addToReversePostOrderListIterative(first, res);
|
addToReversePostOrderListIterative(first, res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addToReversePostOrderListIterative(BasicBlock root, List<BasicBlock> lst) {
|
private static void addToReversePostOrderListIterative(BasicBlock root, List<? super BasicBlock> lst) {
|
||||||
|
|
||||||
LinkedList<BasicBlock> stackNode = new LinkedList<BasicBlock>();
|
LinkedList<BasicBlock> stackNode = new LinkedList<>();
|
||||||
LinkedList<Integer> stackIndex = new LinkedList<Integer>();
|
LinkedList<Integer> stackIndex = new LinkedList<>();
|
||||||
|
|
||||||
Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
|
Set<BasicBlock> setVisited = new HashSet<>();
|
||||||
|
|
||||||
stackNode.add(root);
|
stackNode.add(root);
|
||||||
stackIndex.add(0);
|
stackIndex.add(0);
|
||||||
@ -801,7 +763,7 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
|
|
||||||
setVisited.add(node);
|
setVisited.add(node);
|
||||||
|
|
||||||
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(node.getSuccs());
|
List<BasicBlock> lstSuccs = new ArrayList<>(node.getSuccs());
|
||||||
lstSuccs.addAll(node.getSuccExceptions());
|
lstSuccs.addAll(node.getSuccExceptions());
|
||||||
|
|
||||||
for (; index < lstSuccs.size(); index++) {
|
for (; index < lstSuccs.size(); index++) {
|
||||||
@ -834,10 +796,6 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlocks(VBStyleCollection<BasicBlock, Integer> blocks) {
|
|
||||||
this.blocks = blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicBlock getFirst() {
|
public BasicBlock getFirst() {
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@ -846,39 +804,15 @@ public class ControlFlowGraph implements CodeConstants {
|
|||||||
this.first = first;
|
this.first = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BasicBlock> getEndBlocks() {
|
|
||||||
return last.getPreds();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ExceptionRangeCFG> getExceptions() {
|
public List<ExceptionRangeCFG> getExceptions() {
|
||||||
return exceptions;
|
return exceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExceptions(List<ExceptionRangeCFG> exceptions) {
|
|
||||||
this.exceptions = exceptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicBlock getLast() {
|
public BasicBlock getLast() {
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLast(BasicBlock last) {
|
|
||||||
this.last = last;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<BasicBlock, BasicBlock> getSubroutines() {
|
|
||||||
return subroutines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubroutines(Map<BasicBlock, BasicBlock> subroutines) {
|
|
||||||
this.subroutines = subroutines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<BasicBlock> getFinallyExits() {
|
public Set<BasicBlock> getFinallyExits() {
|
||||||
return finallyExits;
|
return finallyExits;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void setFinallyExits(HashSet<BasicBlock> finallyExits) {
|
|
||||||
this.finallyExits = finallyExits;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +1,15 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.cfg;
|
package org.jetbrains.java.decompiler.code.cfg;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ExceptionRangeCFG {
|
public class ExceptionRangeCFG {
|
||||||
|
private final List<BasicBlock> protectedRange; // FIXME: replace with set
|
||||||
private List<BasicBlock> protectedRange = new ArrayList<BasicBlock>(); // FIXME: replace with set
|
|
||||||
|
|
||||||
private BasicBlock handler;
|
private BasicBlock handler;
|
||||||
|
|
||||||
private List<String> exceptionTypes;
|
private List<String> exceptionTypes;
|
||||||
|
|
||||||
public ExceptionRangeCFG(List<BasicBlock> protectedRange, BasicBlock handler, List<String> exceptionType) {
|
public ExceptionRangeCFG(List<BasicBlock> protectedRange, BasicBlock handler, List<String> exceptionType) {
|
||||||
@ -35,7 +17,7 @@ public class ExceptionRangeCFG {
|
|||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
||||||
if (exceptionType != null) {
|
if (exceptionType != null) {
|
||||||
this.exceptionTypes = new ArrayList<String>(exceptionType);
|
this.exceptionTypes = new ArrayList<>(exceptionType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,22 +25,28 @@ public class ExceptionRangeCFG {
|
|||||||
return protectedRange.contains(handler);
|
return protectedRange.contains(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
|
|
||||||
buf.append("exceptionType:");
|
buf.append("exceptionType:");
|
||||||
for (String exception_type : exceptionTypes) {
|
|
||||||
buf.append(" ").append(exception_type);
|
if (exceptionTypes == null) {
|
||||||
|
buf.append(" null");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
for (String exception_type : exceptionTypes) {
|
||||||
|
buf.append(" ").append(exception_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buf.append(new_line_separator);
|
buf.append(new_line_separator);
|
||||||
|
|
||||||
buf.append("handler: ").append(handler.id).append(new_line_separator);
|
buf.append("handler: ").append(handler.id).append(new_line_separator);
|
||||||
buf.append("range: ");
|
buf.append("range: ");
|
||||||
for (int i = 0; i < protectedRange.size(); i++) {
|
for (BasicBlock block : protectedRange) {
|
||||||
buf.append(protectedRange.get(i).id).append(" ");
|
buf.append(block.id).append(" ");
|
||||||
}
|
}
|
||||||
buf.append(new_line_separator);
|
buf.append(new_line_separator);
|
||||||
|
|
||||||
@ -77,16 +65,11 @@ public class ExceptionRangeCFG {
|
|||||||
return protectedRange;
|
return protectedRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProtectedRange(List<BasicBlock> protectedRange) {
|
|
||||||
this.protectedRange = protectedRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getExceptionTypes() {
|
public List<String> getExceptionTypes() {
|
||||||
return this.exceptionTypes;
|
return this.exceptionTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addExceptionType(String exceptionType) {
|
public void addExceptionType(String exceptionType) {
|
||||||
|
|
||||||
if (this.exceptionTypes == null) {
|
if (this.exceptionTypes == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -100,30 +83,6 @@ public class ExceptionRangeCFG {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getUniqueExceptionsString() {
|
public String getUniqueExceptionsString() {
|
||||||
|
return exceptionTypes != null ? exceptionTypes.stream().distinct().collect(Collectors.joining(":")) : null;
|
||||||
if (exceptionTypes == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> setExceptionStrings = new HashSet<String>();
|
|
||||||
|
|
||||||
for (String exceptionType : exceptionTypes) { // normalize order
|
|
||||||
setExceptionStrings.add(exceptionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
String ret = "";
|
|
||||||
for (String exception : setExceptionStrings) {
|
|
||||||
if (!ret.isEmpty()) {
|
|
||||||
ret += ":";
|
|
||||||
}
|
|
||||||
ret += exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public void setExceptionType(String exceptionType) {
|
|
||||||
// this.exceptionType = exceptionType;
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,31 +1,18 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.interpreter;
|
package org.jetbrains.java.decompiler.code.interpreter;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
import org.jetbrains.java.decompiler.code.Instruction;
|
||||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||||
import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
|
import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
|
||||||
|
import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
|
||||||
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
|
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
|
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
import org.jetbrains.java.decompiler.util.ListStack;
|
import org.jetbrains.java.decompiler.util.ListStack;
|
||||||
|
|
||||||
public class InstructionImpact {
|
public final class InstructionImpact {
|
||||||
|
|
||||||
// {read, write}
|
// {read, write}
|
||||||
private static final int[][][] stack_impact = {
|
private static final int[][][] stack_impact = {
|
||||||
@ -338,7 +325,6 @@ public class InstructionImpact {
|
|||||||
|
|
||||||
|
|
||||||
public static void stepTypes(DataPoint data, Instruction instr, ConstantPool pool) {
|
public static void stepTypes(DataPoint data, Instruction instr, ConstantPool pool) {
|
||||||
|
|
||||||
ListStack<VarType> stack = data.getStack();
|
ListStack<VarType> stack = data.getStack();
|
||||||
int[][] arr = stack_impact[instr.opcode];
|
int[][] arr = stack_impact[instr.opcode];
|
||||||
|
|
||||||
@ -350,8 +336,7 @@ public class InstructionImpact {
|
|||||||
|
|
||||||
if (read != null) {
|
if (read != null) {
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
for (int i = 0; i < read.length; i++) {
|
for (int type : read) {
|
||||||
int type = read[i];
|
|
||||||
depth++;
|
depth++;
|
||||||
if (type == CodeConstants.TYPE_LONG ||
|
if (type == CodeConstants.TYPE_LONG ||
|
||||||
type == CodeConstants.TYPE_DOUBLE) {
|
type == CodeConstants.TYPE_DOUBLE) {
|
||||||
@ -363,8 +348,7 @@ public class InstructionImpact {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (write != null) {
|
if (write != null) {
|
||||||
for (int i = 0; i < write.length; i++) {
|
for (int type : write) {
|
||||||
int type = write[i];
|
|
||||||
stack.push(new VarType(type));
|
stack.push(new VarType(type));
|
||||||
if (type == CodeConstants.TYPE_LONG ||
|
if (type == CodeConstants.TYPE_LONG ||
|
||||||
type == CodeConstants.TYPE_DOUBLE) {
|
type == CodeConstants.TYPE_DOUBLE) {
|
||||||
@ -394,8 +378,8 @@ public class InstructionImpact {
|
|||||||
case CodeConstants.opc_ldc:
|
case CodeConstants.opc_ldc:
|
||||||
case CodeConstants.opc_ldc_w:
|
case CodeConstants.opc_ldc_w:
|
||||||
case CodeConstants.opc_ldc2_w:
|
case CodeConstants.opc_ldc2_w:
|
||||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
PooledConstant constant = pool.getConstant(instr.operand(0));
|
||||||
switch (cn.type) {
|
switch (constant.type) {
|
||||||
case CodeConstants.CONSTANT_Integer:
|
case CodeConstants.CONSTANT_Integer:
|
||||||
stack.push(new VarType(CodeConstants.TYPE_INT));
|
stack.push(new VarType(CodeConstants.TYPE_INT));
|
||||||
break;
|
break;
|
||||||
@ -416,10 +400,13 @@ public class InstructionImpact {
|
|||||||
case CodeConstants.CONSTANT_Class:
|
case CodeConstants.CONSTANT_Class:
|
||||||
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class"));
|
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class"));
|
||||||
break;
|
break;
|
||||||
|
case CodeConstants.CONSTANT_MethodHandle:
|
||||||
|
stack.push(new VarType(((LinkConstant)constant).descriptor));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_aload:
|
case CodeConstants.opc_aload:
|
||||||
var1 = data.getVariable(instr.getOperand(0));
|
var1 = data.getVariable(instr.operand(0));
|
||||||
if (var1 != null) {
|
if (var1 != null) {
|
||||||
stack.push(var1);
|
stack.push(var1);
|
||||||
}
|
}
|
||||||
@ -429,10 +416,10 @@ public class InstructionImpact {
|
|||||||
break;
|
break;
|
||||||
case CodeConstants.opc_aaload:
|
case CodeConstants.opc_aaload:
|
||||||
var1 = stack.pop(2);
|
var1 = stack.pop(2);
|
||||||
stack.push(new VarType(var1.type, var1.arraydim - 1, var1.value));
|
stack.push(new VarType(var1.type, var1.arrayDim - 1, var1.value));
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_astore:
|
case CodeConstants.opc_astore:
|
||||||
data.setVariable(instr.getOperand(0), stack.pop());
|
data.setVariable(instr.operand(0), stack.pop());
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_dup:
|
case CodeConstants.opc_dup:
|
||||||
case CodeConstants.opc_dup_x1:
|
case CodeConstants.opc_dup_x1:
|
||||||
@ -454,19 +441,19 @@ public class InstructionImpact {
|
|||||||
case CodeConstants.opc_getfield:
|
case CodeConstants.opc_getfield:
|
||||||
stack.pop();
|
stack.pop();
|
||||||
case CodeConstants.opc_getstatic:
|
case CodeConstants.opc_getstatic:
|
||||||
ck = pool.getLinkConstant(instr.getOperand(0));
|
ck = pool.getLinkConstant(instr.operand(0));
|
||||||
var1 = new VarType(ck.descriptor);
|
var1 = new VarType(ck.descriptor);
|
||||||
stack.push(var1);
|
stack.push(var1);
|
||||||
if (var1.stack_size == 2) {
|
if (var1.stackSize == 2) {
|
||||||
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
|
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_putfield:
|
case CodeConstants.opc_putfield:
|
||||||
stack.pop();
|
stack.pop();
|
||||||
case CodeConstants.opc_putstatic:
|
case CodeConstants.opc_putstatic:
|
||||||
ck = pool.getLinkConstant(instr.getOperand(0));
|
ck = pool.getLinkConstant(instr.operand(0));
|
||||||
var1 = new VarType(ck.descriptor);
|
var1 = new VarType(ck.descriptor);
|
||||||
stack.pop(var1.stack_size);
|
stack.pop(var1.stackSize);
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_invokevirtual:
|
case CodeConstants.opc_invokevirtual:
|
||||||
case CodeConstants.opc_invokespecial:
|
case CodeConstants.opc_invokespecial:
|
||||||
@ -474,29 +461,27 @@ public class InstructionImpact {
|
|||||||
stack.pop();
|
stack.pop();
|
||||||
case CodeConstants.opc_invokestatic:
|
case CodeConstants.opc_invokestatic:
|
||||||
case CodeConstants.opc_invokedynamic:
|
case CodeConstants.opc_invokedynamic:
|
||||||
if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
|
if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) {
|
||||||
ck = pool.getLinkConstant(instr.getOperand(0));
|
ck = pool.getLinkConstant(instr.operand(0));
|
||||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
|
MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
|
||||||
for (int i = 0; i < md.params.length; i++) {
|
for (int i = 0; i < md.params.length; i++) {
|
||||||
stack.pop(md.params[i].stack_size);
|
stack.pop(md.params[i].stackSize);
|
||||||
}
|
}
|
||||||
if (md.ret.type != CodeConstants.TYPE_VOID) {
|
if (md.ret.type != CodeConstants.TYPE_VOID) {
|
||||||
stack.push(md.ret);
|
stack.push(md.ret);
|
||||||
if (md.ret.stack_size == 2) {
|
if (md.ret.stackSize == 2) {
|
||||||
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
|
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_new:
|
case CodeConstants.opc_new:
|
||||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
cn = pool.getPrimitiveConstant(instr.operand(0));
|
||||||
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
|
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_newarray:
|
case CodeConstants.opc_newarray:
|
||||||
stack.pop();
|
stack.pop();
|
||||||
var1 = new VarType(arr_type[instr.getOperand(0) - 4]);
|
stack.push(new VarType(arr_type[instr.operand(0) - 4], 1).resizeArrayDim(1));
|
||||||
var1.arraydim = 1;
|
|
||||||
stack.push(var1);
|
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_athrow:
|
case CodeConstants.opc_athrow:
|
||||||
var1 = stack.pop();
|
var1 = stack.pop();
|
||||||
@ -506,17 +491,17 @@ public class InstructionImpact {
|
|||||||
case CodeConstants.opc_checkcast:
|
case CodeConstants.opc_checkcast:
|
||||||
case CodeConstants.opc_instanceof:
|
case CodeConstants.opc_instanceof:
|
||||||
stack.pop();
|
stack.pop();
|
||||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
cn = pool.getPrimitiveConstant(instr.operand(0));
|
||||||
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
|
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
|
||||||
break;
|
break;
|
||||||
case CodeConstants.opc_anewarray:
|
case CodeConstants.opc_anewarray:
|
||||||
case CodeConstants.opc_multianewarray:
|
case CodeConstants.opc_multianewarray:
|
||||||
int dimensions = (instr.opcode == CodeConstants.opc_anewarray) ? 1 : instr.getOperand(1);
|
int dimensions = (instr.opcode == CodeConstants.opc_anewarray) ? 1 : instr.operand(1);
|
||||||
stack.pop(dimensions);
|
stack.pop(dimensions);
|
||||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
cn = pool.getPrimitiveConstant(instr.operand(0));
|
||||||
if (cn.isArray) {
|
if (cn.isArray) {
|
||||||
var1 = new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString());
|
var1 = new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString());
|
||||||
var1.arraydim += dimensions;
|
var1 = var1.resizeArrayDim(var1.arrayDim + dimensions);
|
||||||
stack.push(var1);
|
stack.push(var1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1,286 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.interpreter;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: move to StructContext
|
|
||||||
public class Util {
|
|
||||||
|
|
||||||
private static final String[][] runtime_exceptions = {
|
|
||||||
|
|
||||||
null, // public final static int opc_nop = 0;
|
|
||||||
null, // public final static int opc_aconst_null = 1;
|
|
||||||
null, // public final static int opc_iconst_m1 = 2;
|
|
||||||
null, // public final static int opc_iconst_0 = 3;
|
|
||||||
null, // public final static int opc_iconst_1 = 4;
|
|
||||||
null, // public final static int opc_iconst_2 = 5;
|
|
||||||
null, // public final static int opc_iconst_3 = 6;
|
|
||||||
null, // public final static int opc_iconst_4 = 7;
|
|
||||||
null, // public final static int opc_iconst_5 = 8;
|
|
||||||
null, // public final static int opc_lconst_0 = 9;
|
|
||||||
null, // public final static int opc_lconst_1 = 10;
|
|
||||||
null, // public final static int opc_fconst_0 = 11;
|
|
||||||
null, // public final static int opc_fconst_1 = 12;
|
|
||||||
null, // public final static int opc_fconst_2 = 13;
|
|
||||||
null, // public final static int opc_dconst_0 = 14;
|
|
||||||
null, // public final static int opc_dconst_1 = 15;
|
|
||||||
null, // public final static int opc_bipush = 16;
|
|
||||||
null, // public final static int opc_sipush = 17;
|
|
||||||
null, // public final static int opc_ldc = 18;
|
|
||||||
null, // public final static int opc_ldc_w = 19;
|
|
||||||
null, // public final static int opc_ldc2_w = 20;
|
|
||||||
null, // public final static int opc_iload = 21;
|
|
||||||
null, // public final static int opc_lload = 22;
|
|
||||||
null, // public final static int opc_fload = 23;
|
|
||||||
null, // public final static int opc_dload = 24;
|
|
||||||
null, // public final static int opc_aload = 25;
|
|
||||||
null, // public final static int opc_iload_0 = 26;
|
|
||||||
null, // public final static int opc_iload_1 = 27;
|
|
||||||
null, // public final static int opc_iload_2 = 28;
|
|
||||||
null, // public final static int opc_iload_3 = 29;
|
|
||||||
null, // public final static int opc_lload_0 = 30;
|
|
||||||
null, // public final static int opc_lload_1 = 31;
|
|
||||||
null, // public final static int opc_lload_2 = 32;
|
|
||||||
null, // public final static int opc_lload_3 = 33;
|
|
||||||
null, // public final static int opc_fload_0 = 34;
|
|
||||||
null, // public final static int opc_fload_1 = 35;
|
|
||||||
null, // public final static int opc_fload_2 = 36;
|
|
||||||
null, // public final static int opc_fload_3 = 37;
|
|
||||||
null, // public final static int opc_dload_0 = 38;
|
|
||||||
null, // public final static int opc_dload_1 = 39;
|
|
||||||
null, // public final static int opc_dload_2 = 40;
|
|
||||||
null, // public final static int opc_dload_3 = 41;
|
|
||||||
null, // public final static int opc_aload_0 = 42;
|
|
||||||
null, // public final static int opc_aload_1 = 43;
|
|
||||||
null, // public final static int opc_aload_2 = 44;
|
|
||||||
null, // public final static int opc_aload_3 = 45;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_iaload = 46;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_laload = 47;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_faload = 48;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_daload = 49;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_aaload = 50;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_baload = 51;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_caload = 52;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_saload = 53;
|
|
||||||
null, // public final static int opc_istore = 54;
|
|
||||||
null, // public final static int opc_lstore = 55;
|
|
||||||
null, // public final static int opc_fstore = 56;
|
|
||||||
null, // public final static int opc_dstore = 57;
|
|
||||||
null, // public final static int opc_astore = 58;
|
|
||||||
null, // public final static int opc_istore_0 = 59;
|
|
||||||
null, // public final static int opc_istore_1 = 60;
|
|
||||||
null, // public final static int opc_istore_2 = 61;
|
|
||||||
null, // public final static int opc_istore_3 = 62;
|
|
||||||
null, // public final static int opc_lstore_0 = 63;
|
|
||||||
null, // public final static int opc_lstore_1 = 64;
|
|
||||||
null, // public final static int opc_lstore_2 = 65;
|
|
||||||
null, // public final static int opc_lstore_3 = 66;
|
|
||||||
null, // public final static int opc_fstore_0 = 67;
|
|
||||||
null, // public final static int opc_fstore_1 = 68;
|
|
||||||
null, // public final static int opc_fstore_2 = 69;
|
|
||||||
null, // public final static int opc_fstore_3 = 70;
|
|
||||||
null, // public final static int opc_dstore_0 = 71;
|
|
||||||
null, // public final static int opc_dstore_1 = 72;
|
|
||||||
null, // public final static int opc_dstore_2 = 73;
|
|
||||||
null, // public final static int opc_dstore_3 = 74;
|
|
||||||
null, // public final static int opc_astore_0 = 75;
|
|
||||||
null, // public final static int opc_astore_1 = 76;
|
|
||||||
null, // public final static int opc_astore_2 = 77;
|
|
||||||
null, // public final static int opc_astore_3 = 78;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_iastore = 79;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_lastore = 80;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_fastore = 81;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_dastore = 82;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException", "java/lang/ArrayStoreException"},
|
|
||||||
// public final static int opc_aastore = 83;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_bastore = 84;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_castore = 85;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
|
|
||||||
// public final static int opc_sastore = 86;
|
|
||||||
null, // public final static int opc_pop = 87;
|
|
||||||
null, // public final static int opc_pop2 = 88;
|
|
||||||
null, // public final static int opc_dup = 89;
|
|
||||||
null, // public final static int opc_dup_x1 = 90;
|
|
||||||
null, // public final static int opc_dup_x2 = 91;
|
|
||||||
null, // public final static int opc_dup2 = 92;
|
|
||||||
null, // public final static int opc_dup2_x1 = 93;
|
|
||||||
null, // public final static int opc_dup2_x2 = 94;
|
|
||||||
null, // public final static int opc_swap = 95;
|
|
||||||
null, // public final static int opc_iadd = 96;
|
|
||||||
null, // public final static int opc_ladd = 97;
|
|
||||||
null, // public final static int opc_fadd = 98;
|
|
||||||
null, // public final static int opc_dadd = 99;
|
|
||||||
null, // public final static int opc_isub = 100;
|
|
||||||
null, // public final static int opc_lsub = 101;
|
|
||||||
null, // public final static int opc_fsub = 102;
|
|
||||||
null, // public final static int opc_dsub = 103;
|
|
||||||
null, // public final static int opc_imul = 104;
|
|
||||||
null, // public final static int opc_lmul = 105;
|
|
||||||
null, // public final static int opc_fmul = 106;
|
|
||||||
null, // public final static int opc_dmul = 107;
|
|
||||||
{"java/lang/ArithmeticException"}, // public final static int opc_idiv = 108;
|
|
||||||
{"java/lang/ArithmeticException"}, // public final static int opc_ldiv = 109;
|
|
||||||
null, // public final static int opc_fdiv = 110;
|
|
||||||
null, // public final static int opc_ddiv = 111;
|
|
||||||
{"java/lang/ArithmeticException"}, // public final static int opc_irem = 112;
|
|
||||||
{"java/lang/ArithmeticException"}, // public final static int opc_lrem = 113;
|
|
||||||
null, // public final static int opc_frem = 114;
|
|
||||||
null, // public final static int opc_drem = 115;
|
|
||||||
null, // public final static int opc_ineg = 116;
|
|
||||||
null, // public final static int opc_lneg = 117;
|
|
||||||
null, // public final static int opc_fneg = 118;
|
|
||||||
null, // public final static int opc_dneg = 119;
|
|
||||||
null, // public final static int opc_ishl = 120;
|
|
||||||
null, // public final static int opc_lshl = 121;
|
|
||||||
null, // public final static int opc_ishr = 122;
|
|
||||||
null, // public final static int opc_lshr = 123;
|
|
||||||
null, // public final static int opc_iushr = 124;
|
|
||||||
null, // public final static int opc_lushr = 125;
|
|
||||||
null, // public final static int opc_iand = 126;
|
|
||||||
null, // public final static int opc_land = 127;
|
|
||||||
null, // public final static int opc_ior = 128;
|
|
||||||
null, // public final static int opc_lor = 129;
|
|
||||||
null, // public final static int opc_ixor = 130;
|
|
||||||
null, // public final static int opc_lxor = 131;
|
|
||||||
null, // public final static int opc_iinc = 132;
|
|
||||||
null, // public final static int opc_i2l = 133;
|
|
||||||
null, // public final static int opc_i2f = 134;
|
|
||||||
null, // public final static int opc_i2d = 135;
|
|
||||||
null, // public final static int opc_l2i = 136;
|
|
||||||
null, // public final static int opc_l2f = 137;
|
|
||||||
null, // public final static int opc_l2d = 138;
|
|
||||||
null, // public final static int opc_f2i = 139;
|
|
||||||
null, // public final static int opc_f2l = 140;
|
|
||||||
null, // public final static int opc_f2d = 141;
|
|
||||||
null, // public final static int opc_d2i = 142;
|
|
||||||
null, // public final static int opc_d2l = 143;
|
|
||||||
null, // public final static int opc_d2f = 144;
|
|
||||||
null, // public final static int opc_i2b = 145;
|
|
||||||
null, // public final static int opc_i2c = 146;
|
|
||||||
null, // public final static int opc_i2s = 147;
|
|
||||||
null, // public final static int opc_lcmp = 148;
|
|
||||||
null, // public final static int opc_fcmpl = 149;
|
|
||||||
null, // public final static int opc_fcmpg = 150;
|
|
||||||
null, // public final static int opc_dcmpl = 151;
|
|
||||||
null, // public final static int opc_dcmpg = 152;
|
|
||||||
null, // public final static int opc_ifeq = 153;
|
|
||||||
null, // public final static int opc_ifne = 154;
|
|
||||||
null, // public final static int opc_iflt = 155;
|
|
||||||
null, // public final static int opc_ifge = 156;
|
|
||||||
null, // public final static int opc_ifgt = 157;
|
|
||||||
null, // public final static int opc_ifle = 158;
|
|
||||||
null, // public final static int opc_if_icmpeq = 159;
|
|
||||||
null, // public final static int opc_if_icmpne = 160;
|
|
||||||
null, // public final static int opc_if_icmplt = 161;
|
|
||||||
null, // public final static int opc_if_icmpge = 162;
|
|
||||||
null, // public final static int opc_if_icmpgt = 163;
|
|
||||||
null, // public final static int opc_if_icmple = 164;
|
|
||||||
null, // public final static int opc_if_acmpeq = 165;
|
|
||||||
null, // public final static int opc_if_acmpne = 166;
|
|
||||||
null, // public final static int opc_goto = 167;
|
|
||||||
null, // public final static int opc_jsr = 168;
|
|
||||||
null, // public final static int opc_ret = 169;
|
|
||||||
null, // public final static int opc_tableswitch = 170;
|
|
||||||
null, // public final static int opc_lookupswitch = 171;
|
|
||||||
{"java/lang/IllegalMonitorStateException"}, // public final static int opc_ireturn = 172;
|
|
||||||
{"java/lang/IllegalMonitorStateException"}, // public final static int opc_lreturn = 173;
|
|
||||||
{"java/lang/IllegalMonitorStateException"}, // public final static int opc_freturn = 174;
|
|
||||||
{"java/lang/IllegalMonitorStateException"}, // public final static int opc_dreturn = 175;
|
|
||||||
{"java/lang/IllegalMonitorStateException"}, // public final static int opc_areturn = 176;
|
|
||||||
{"java/lang/IllegalMonitorStateException"}, // public final static int opc_return = 177;
|
|
||||||
null, // public final static int opc_getstatic = 178;
|
|
||||||
null, // public final static int opc_putstatic = 179;
|
|
||||||
{"java/lang/NullPointerException"}, // public final static int opc_getfield = 180;
|
|
||||||
{"java/lang/NullPointerException"}, // public final static int opc_putfield = 181;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"},
|
|
||||||
// public final static int opc_invokevirtual = 182;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/UnsatisfiedLinkError"},
|
|
||||||
// public final static int opc_invokespecial = 183;
|
|
||||||
{"java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokestatic = 184;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/IncompatibleClassChangeError", "java/lang/IllegalAccessError",
|
|
||||||
"java/lang/java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"},
|
|
||||||
// public final static int opc_invokeinterface = 185;
|
|
||||||
null, // public final static int opc_xxxunusedxxx = 186;
|
|
||||||
null, // public final static int opc_new = 187;
|
|
||||||
{"java/lang/NegativeArraySizeException"}, // public final static int opc_newarray = 188;
|
|
||||||
{"java/lang/NegativeArraySizeException"}, // public final static int opc_anewarray = 189;
|
|
||||||
{"java/lang/NullPointerException"}, // public final static int opc_arraylength = 190;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"},
|
|
||||||
// public final static int opc_athrow = 191;
|
|
||||||
{"java/lang/ClassCastException"}, // public final static int opc_checkcast = 192;
|
|
||||||
null, // public final static int opc_instanceof = 193;
|
|
||||||
{"java/lang/NullPointerException"}, // public final static int opc_monitorenter = 194;
|
|
||||||
{"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"},
|
|
||||||
// public final static int opc_monitorexit = 195;
|
|
||||||
null, // public final static int opc_wide = 196;
|
|
||||||
{"java/lang/NegativeArraySizeException"}, // public final static int opc_multianewarray = 197;
|
|
||||||
null, // public final static int opc_ifnull = 198;
|
|
||||||
null, // public final static int opc_ifnonnull = 199;
|
|
||||||
null, // public final static int opc_goto_w = 200;
|
|
||||||
null, // public final static int opc_jsr_w = 201;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean instanceOf(StructContext context, String valclass, String refclass) {
|
|
||||||
|
|
||||||
if (valclass.equals(refclass)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StructClass cl = context.getClass(valclass);
|
|
||||||
if (cl == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cl.superClass != null && instanceOf(context, cl.superClass.getString(), refclass)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] interfaces = cl.getInterfaces();
|
|
||||||
for (int i = 0; i < interfaces.length; i++) {
|
|
||||||
String intfc = cl.getPool().getPrimitiveConstant(interfaces[i]).getString();
|
|
||||||
|
|
||||||
if (instanceOf(context, intfc, refclass)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String[] getRuntimeExceptions(Instruction instr) {
|
|
||||||
return runtime_exceptions[instr.opcode];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ALOAD extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_aload_0, opc_aload_1, opc_aload_2, opc_aload_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_aload);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ANEWARRAY extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_anewarray);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ASTORE extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_astore_0, opc_astore_1, opc_astore_2, opc_astore_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_astore);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class BIPUSH extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes =
|
|
||||||
new int[]{opc_iconst_m1, opc_iconst_0, opc_iconst_1, opc_iconst_2, opc_iconst_3, opc_iconst_4, opc_iconst_5};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int value = getOperand(0);
|
|
||||||
if (value < -1 || value > 5) {
|
|
||||||
out.writeByte(opc_bipush);
|
|
||||||
out.writeByte(value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[value + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int value = getOperand(0);
|
|
||||||
if (value < -1 || value > 5) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class CHECKCAST extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_checkcast);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class DLOAD extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_dload_0, opc_dload_1, opc_dload_2, opc_dload_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_dload);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class DSTORE extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_dstore_0, opc_dstore_1, opc_dstore_2, opc_dstore_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_dstore);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class FLOAD extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_fload_0, opc_fload_1, opc_fload_2, opc_fload_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_fload);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class FSTORE extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_fstore_0, opc_fstore_1, opc_fstore_2, opc_fstore_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_fstore);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GETFIELD extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_getfield);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GETSTATIC extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_getstatic);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.JumpInstruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GOTO extends JumpInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int operand = getOperand(0);
|
|
||||||
if (operand < -32768 || operand > 32767) {
|
|
||||||
out.writeByte(opc_goto_w);
|
|
||||||
out.writeInt(operand);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opc_goto);
|
|
||||||
out.writeShort(operand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int operand = getOperand(0);
|
|
||||||
if (operand < -32768 || operand > 32767) {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.JumpInstruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GOTO_W extends JumpInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_goto_w);
|
|
||||||
out.writeInt(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class IINC extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_iinc);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
out.writeShort(getOperand(1));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(getOperand(0));
|
|
||||||
out.writeByte(getOperand(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return wide ? 6 : 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ILOAD extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_iload_0, opc_iload_1, opc_iload_2, opc_iload_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_iload);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
return wide ? 4 : 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class INSTANCEOF extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_instanceof);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class INVOKEINTERFACE extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_invokeinterface);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
out.writeByte(getOperand(1));
|
|
||||||
out.writeByte(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class INVOKESPECIAL extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_invokespecial);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class INVOKESTATIC extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_invokestatic);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class INVOKEVIRTUAL extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_invokevirtual);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ISTORE extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_istore_0, opc_istore_1, opc_istore_2, opc_istore_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_istore);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
return wide ? 4 : 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.JumpInstruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class JSR extends JumpInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int operand = getOperand(0);
|
|
||||||
if (operand < -32768 || operand > 32767) {
|
|
||||||
out.writeByte(opc_jsr_w);
|
|
||||||
out.writeInt(operand);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opc_jsr);
|
|
||||||
out.writeShort(operand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int operand = getOperand(0);
|
|
||||||
if (operand < -32768 || operand > 32767) {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.JumpInstruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class JSR_W extends JumpInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_jsr_w);
|
|
||||||
out.writeInt(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LDC extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_ldc);
|
|
||||||
out.writeByte(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LDC2_W extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_ldc2_w);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LDC_W extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_ldc_w);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LLOAD extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_lload_0, opc_lload_1, opc_lload_2, opc_lload_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_lload);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
return wide ? 4 : 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.SwitchInstruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LOOKUPSWITCH extends SwitchInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
|
|
||||||
out.writeByte(opc_lookupswitch);
|
|
||||||
|
|
||||||
int padding = 3 - (offset % 4);
|
|
||||||
for (int i = 0; i < padding; i++) {
|
|
||||||
out.writeByte(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < operandsCount(); i++) {
|
|
||||||
out.writeInt(getOperand(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 1 + operandsCount() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LSTORE extends Instruction {
|
|
||||||
|
|
||||||
private static int[] opcodes = new int[]{opc_lstore_0, opc_lstore_1, opc_lstore_2, opc_lstore_3};
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_lstore);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(opcodes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
int index = getOperand(0);
|
|
||||||
if (index > 3) {
|
|
||||||
return wide ? 4 : 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class MULTIANEWARRAY extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_multianewarray);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
out.writeByte(getOperand(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class NEW extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_new);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class NEWARRAY extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_newarray);
|
|
||||||
out.writeByte(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class PUTFIELD extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_putfield);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class PUTSTATIC extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_putstatic);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class RET extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
if (wide) {
|
|
||||||
out.writeByte(opc_wide);
|
|
||||||
}
|
|
||||||
out.writeByte(opc_ret);
|
|
||||||
if (wide) {
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.writeByte(getOperand(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return wide ? 4 : 2;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class SIPUSH extends Instruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
out.writeByte(opc_sipush);
|
|
||||||
out.writeShort(getOperand(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.code.optinstructions;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.SwitchInstruction;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class TABLESWITCH extends SwitchInstruction {
|
|
||||||
|
|
||||||
public void writeToStream(DataOutputStream out, int offset) throws IOException {
|
|
||||||
|
|
||||||
out.writeByte(opc_tableswitch);
|
|
||||||
|
|
||||||
int padding = 3 - (offset % 4);
|
|
||||||
for (int i = 0; i < padding; i++) {
|
|
||||||
out.writeByte(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < operandsCount(); i++) {
|
|
||||||
out.writeInt(getOperand(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return 1 + operandsCount() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -35,13 +21,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AssertProcessor {
|
public final class AssertProcessor {
|
||||||
|
|
||||||
private static final VarType CLASS_ASSERTION_ERROR = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/AssertionError");
|
private static final VarType CLASS_ASSERTION_ERROR = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/AssertionError");
|
||||||
|
|
||||||
public static void buildAssertions(ClassNode node) {
|
public static void buildAssertions(ClassNode node) {
|
||||||
|
|
||||||
ClassWrapper wrapper = node.wrapper;
|
ClassWrapper wrapper = node.getWrapper();
|
||||||
|
|
||||||
StructField field = findAssertionField(node);
|
StructField field = findAssertionField(node);
|
||||||
|
|
||||||
@ -67,7 +53,7 @@ public class AssertProcessor {
|
|||||||
|
|
||||||
private static StructField findAssertionField(ClassNode node) {
|
private static StructField findAssertionField(ClassNode node) {
|
||||||
|
|
||||||
ClassWrapper wrapper = node.wrapper;
|
ClassWrapper wrapper = node.getWrapper();
|
||||||
|
|
||||||
boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
|
boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
|
||||||
|
|
||||||
@ -89,7 +75,7 @@ public class AssertProcessor {
|
|||||||
if (initializer.type == Exprent.EXPRENT_FUNCTION) {
|
if (initializer.type == Exprent.EXPRENT_FUNCTION) {
|
||||||
FunctionExprent fexpr = (FunctionExprent)initializer;
|
FunctionExprent fexpr = (FunctionExprent)initializer;
|
||||||
|
|
||||||
if (fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
|
if (fexpr.getFuncType() == FunctionExprent.FUNCTION_BOOL_NOT &&
|
||||||
fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_INVOCATION) {
|
fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_INVOCATION) {
|
||||||
|
|
||||||
InvocationExprent invexpr = (InvocationExprent)fexpr.getLstOperands().get(0);
|
InvocationExprent invexpr = (InvocationExprent)fexpr.getLstOperands().get(0);
|
||||||
@ -101,11 +87,11 @@ public class AssertProcessor {
|
|||||||
invexpr.getLstParameters().isEmpty()) {
|
invexpr.getLstParameters().isEmpty()) {
|
||||||
|
|
||||||
ConstExprent cexpr = (ConstExprent)invexpr.getInstance();
|
ConstExprent cexpr = (ConstExprent)invexpr.getInstance();
|
||||||
if (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype())) {
|
if (VarType.VARTYPE_CLASS.equals(cexpr.getConstType())) {
|
||||||
|
|
||||||
ClassNode nd = node;
|
ClassNode nd = node;
|
||||||
while (nd != null) {
|
while (nd != null) {
|
||||||
if (nd.wrapper.getClassStruct().qualifiedName.equals(cexpr.getValue())) {
|
if (nd.getWrapper().getClassStruct().qualifiedName.equals(cexpr.getValue())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nd = nd.parent;
|
nd = nd.parent;
|
||||||
@ -157,26 +143,42 @@ public class AssertProcessor {
|
|||||||
|
|
||||||
private static boolean replaceAssertion(Statement parent, IfStatement stat, String classname, String key) {
|
private static boolean replaceAssertion(Statement parent, IfStatement stat, String classname, String key) {
|
||||||
|
|
||||||
|
boolean throwInIf = true;
|
||||||
Statement ifstat = stat.getIfstat();
|
Statement ifstat = stat.getIfstat();
|
||||||
InvocationExprent throwError = isAssertionError(ifstat);
|
InvocationExprent throwError = isAssertionError(ifstat);
|
||||||
|
|
||||||
if (throwError == null) {
|
if (throwError == null) {
|
||||||
return false;
|
//check else:
|
||||||
|
Statement elsestat = stat.getElsestat();
|
||||||
|
throwError = isAssertionError(elsestat);
|
||||||
|
if (throwError == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throwInIf = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object[] exprres = getAssertionExprent(stat.getHeadexprent().getCondition().copy(), classname, key);
|
|
||||||
|
Object[] exprres = getAssertionExprent(stat.getHeadexprent().getCondition().copy(), classname, key, throwInIf);
|
||||||
if (!(Boolean)exprres[1]) {
|
if (!(Boolean)exprres[1]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Exprent> lstParams = new ArrayList<Exprent>();
|
List<Exprent> lstParams = new ArrayList<>();
|
||||||
|
|
||||||
Exprent ascond = null, retcond = null;
|
Exprent ascond = null, retcond = null;
|
||||||
if (exprres[0] != null) {
|
if (throwInIf) {
|
||||||
ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
|
if (exprres[0] != null) {
|
||||||
Arrays.asList(new Exprent[]{(Exprent)exprres[0]}));
|
ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, (Exprent)exprres[0], throwError.bytecode);
|
||||||
retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
|
retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ascond = (Exprent) exprres[0];
|
||||||
|
retcond = ascond;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
lstParams.add(retcond == null ? ascond : retcond);
|
lstParams.add(retcond == null ? ascond : retcond);
|
||||||
if (!throwError.getLstParameters().isEmpty()) {
|
if (!throwError.getLstParameters().isEmpty()) {
|
||||||
@ -197,13 +199,18 @@ public class AssertProcessor {
|
|||||||
first.removeSuccessor(stat.getIfEdge());
|
first.removeSuccessor(stat.getIfEdge());
|
||||||
first.removeSuccessor(stat.getElseEdge());
|
first.removeSuccessor(stat.getElseEdge());
|
||||||
|
|
||||||
List<Statement> lstStatements = new ArrayList<Statement>();
|
List<Statement> lstStatements = new ArrayList<>();
|
||||||
if (first.getExprents() != null && !first.getExprents().isEmpty()) {
|
if (first.getExprents() != null && !first.getExprents().isEmpty()) {
|
||||||
lstStatements.add(first);
|
lstStatements.add(first);
|
||||||
}
|
}
|
||||||
lstStatements.add(newstat);
|
lstStatements.add(newstat);
|
||||||
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||||
lstStatements.add(stat.getElsestat());
|
if (throwInIf) {
|
||||||
|
lstStatements.add(stat.getElsestat());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lstStatements.add(stat.getIfstat());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SequenceStatement sequence = new SequenceStatement(lstStatements);
|
SequenceStatement sequence = new SequenceStatement(lstStatements);
|
||||||
@ -214,10 +221,16 @@ public class AssertProcessor {
|
|||||||
sequence.getStats().get(i), sequence.getStats().get(i + 1)));
|
sequence.getStats().get(i), sequence.getStats().get(i + 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
if (stat.iftype == IfStatement.IFTYPE_IFELSE || !throwInIf) {
|
||||||
Statement ifelse = stat.getElsestat();
|
Statement stmts;
|
||||||
|
if (throwInIf) {
|
||||||
|
stmts = stat.getElsestat();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stmts = stat.getIfstat();
|
||||||
|
}
|
||||||
|
|
||||||
List<StatEdge> lstSuccs = ifelse.getAllSuccessorEdges();
|
List<StatEdge> lstSuccs = stmts.getAllSuccessorEdges();
|
||||||
if (!lstSuccs.isEmpty()) {
|
if (!lstSuccs.isEmpty()) {
|
||||||
StatEdge endedge = lstSuccs.get(0);
|
StatEdge endedge = lstSuccs.get(0);
|
||||||
if (endedge.closure == stat) {
|
if (endedge.closure == stat) {
|
||||||
@ -245,9 +258,9 @@ public class AssertProcessor {
|
|||||||
|
|
||||||
if (expr.type == Exprent.EXPRENT_EXIT) {
|
if (expr.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent exexpr = (ExitExprent)expr;
|
ExitExprent exexpr = (ExitExprent)expr;
|
||||||
if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_NEW) {
|
if (exexpr.getExitType() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_NEW) {
|
||||||
NewExprent nexpr = (NewExprent)exexpr.getValue();
|
NewExprent nexpr = (NewExprent)exexpr.getValue();
|
||||||
if (CLASS_ASSERTION_ERROR.equals(nexpr.getNewtype()) && nexpr.getConstructor() != null) {
|
if (CLASS_ASSERTION_ERROR.equals(nexpr.getNewType()) && nexpr.getConstructor() != null) {
|
||||||
return nexpr.getConstructor();
|
return nexpr.getConstructor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,16 +269,21 @@ public class AssertProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object[] getAssertionExprent(Exprent exprent, String classname, String key) {
|
private static Object[] getAssertionExprent(Exprent exprent, String classname, String key, boolean throwInIf) {
|
||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
||||||
|
int desiredOperation = FunctionExprent.FUNCTION_CADD;
|
||||||
|
if (!throwInIf) {
|
||||||
|
desiredOperation = FunctionExprent.FUNCTION_COR;
|
||||||
|
}
|
||||||
|
|
||||||
FunctionExprent fexpr = (FunctionExprent)exprent;
|
FunctionExprent fexpr = (FunctionExprent)exprent;
|
||||||
if (fexpr.getFunctype() == FunctionExprent.FUNCTION_CADD) {
|
if (fexpr.getFuncType() == desiredOperation) {
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
Exprent param = fexpr.getLstOperands().get(i);
|
Exprent param = fexpr.getLstOperands().get(i);
|
||||||
|
|
||||||
if (isAssertionField(param, classname, key)) {
|
if (isAssertionField(param, classname, key, throwInIf)) {
|
||||||
return new Object[]{fexpr.getLstOperands().get(1 - i), true};
|
return new Object[]{fexpr.getLstOperands().get(1 - i), true};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,7 +291,7 @@ public class AssertProcessor {
|
|||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
Exprent param = fexpr.getLstOperands().get(i);
|
Exprent param = fexpr.getLstOperands().get(i);
|
||||||
|
|
||||||
Object[] res = getAssertionExprent(param, classname, key);
|
Object[] res = getAssertionExprent(param, classname, key, throwInIf);
|
||||||
if ((Boolean)res[1]) {
|
if ((Boolean)res[1]) {
|
||||||
if (param != res[0]) {
|
if (param != res[0]) {
|
||||||
fexpr.getLstOperands().set(i, (Exprent)res[0]);
|
fexpr.getLstOperands().set(i, (Exprent)res[0]);
|
||||||
@ -282,7 +300,7 @@ public class AssertProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isAssertionField(fexpr, classname, key)) {
|
else if (isAssertionField(fexpr, classname, key, throwInIf)) {
|
||||||
// assert false;
|
// assert false;
|
||||||
return new Object[]{null, true};
|
return new Object[]{null, true};
|
||||||
}
|
}
|
||||||
@ -291,20 +309,25 @@ public class AssertProcessor {
|
|||||||
return new Object[]{exprent, false};
|
return new Object[]{exprent, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAssertionField(Exprent exprent, String classname, String key) {
|
private static boolean isAssertionField(Exprent exprent, String classname, String key, boolean throwInIf) {
|
||||||
|
if (throwInIf) {
|
||||||
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
||||||
FunctionExprent fparam = (FunctionExprent)exprent;
|
FunctionExprent fparam = (FunctionExprent)exprent;
|
||||||
if (fparam.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
|
if (fparam.getFuncType() == FunctionExprent.FUNCTION_BOOL_NOT &&
|
||||||
fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
|
fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
|
||||||
FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
|
FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
|
||||||
if (classname.equals(fdparam.getClassname())
|
return classname.equals(fdparam.getClassname()) &&
|
||||||
&& key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString))) {
|
key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (exprent.type == Exprent.EXPRENT_FIELD) {
|
||||||
|
FieldExprent fdparam = (FieldExprent) exprent;
|
||||||
|
return classname.equals(fdparam.getClassname()) &&
|
||||||
|
key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString));
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -36,79 +22,48 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public class ClassReference14Processor {
|
public final class ClassReference14Processor {
|
||||||
|
private static final ExitExprent BODY_EXPR;
|
||||||
|
private static final ExitExprent HANDLER_EXPR;
|
||||||
|
|
||||||
public ExitExprent bodyexprent;
|
static {
|
||||||
|
InvocationExprent invFor = new InvocationExprent();
|
||||||
|
invFor.setName("forName");
|
||||||
|
invFor.setClassname("java/lang/Class");
|
||||||
|
invFor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
|
invFor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
|
||||||
|
invFor.setStatic(true);
|
||||||
|
invFor.setLstParameters(Collections.singletonList(new VarExprent(0, VarType.VARTYPE_STRING, null)));
|
||||||
|
BODY_EXPR = new ExitExprent(ExitExprent.EXIT_RETURN, invFor, VarType.VARTYPE_CLASS, null);
|
||||||
|
|
||||||
public ExitExprent handlerexprent;
|
InvocationExprent ctor = new InvocationExprent();
|
||||||
|
ctor.setName(CodeConstants.INIT_NAME);
|
||||||
|
ctor.setClassname("java/lang/NoClassDefFoundError");
|
||||||
public ClassReference14Processor() {
|
ctor.setStringDescriptor("()V");
|
||||||
|
ctor.setFunctype(InvocationExprent.TYP_INIT);
|
||||||
InvocationExprent invfor = new InvocationExprent();
|
ctor.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
|
||||||
invfor.setName("forName");
|
NewExprent newExpr = new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<>(), null);
|
||||||
invfor.setClassname("java/lang/Class");
|
newExpr.setConstructor(ctor);
|
||||||
invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
|
InvocationExprent invCause = new InvocationExprent();
|
||||||
invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
|
invCause.setName("initCause");
|
||||||
invfor.setStatic(true);
|
invCause.setClassname("java/lang/NoClassDefFoundError");
|
||||||
invfor.setLstParameters(Arrays.asList(new Exprent[]{new VarExprent(0, VarType.VARTYPE_STRING, null)}));
|
invCause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
|
||||||
|
invCause.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
|
||||||
bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN,
|
invCause.setInstance(newExpr);
|
||||||
invfor,
|
invCause.setLstParameters(
|
||||||
VarType.VARTYPE_CLASS);
|
Collections.singletonList(new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)));
|
||||||
|
HANDLER_EXPR = new ExitExprent(ExitExprent.EXIT_THROW, invCause, null, null);
|
||||||
InvocationExprent constr = new InvocationExprent();
|
|
||||||
constr.setName("<init>");
|
|
||||||
constr.setClassname("java/lang/NoClassDefFoundError");
|
|
||||||
constr.setStringDescriptor("()V");
|
|
||||||
constr.setFunctype(InvocationExprent.TYP_INIT);
|
|
||||||
constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
|
|
||||||
|
|
||||||
NewExprent newexpr =
|
|
||||||
new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<Exprent>());
|
|
||||||
newexpr.setConstructor(constr);
|
|
||||||
|
|
||||||
InvocationExprent invcause = new InvocationExprent();
|
|
||||||
invcause.setName("initCause");
|
|
||||||
invcause.setClassname("java/lang/NoClassDefFoundError");
|
|
||||||
invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
|
|
||||||
invcause.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
|
|
||||||
invcause.setInstance(newexpr);
|
|
||||||
invcause.setLstParameters(
|
|
||||||
Arrays.asList(new Exprent[]{new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)}));
|
|
||||||
|
|
||||||
handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW,
|
|
||||||
invcause,
|
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void processClassReferences(ClassNode node) {
|
||||||
public void processClassReferences(ClassNode node) {
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
// // 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
|
// find the synthetic method Class class$(String) if present
|
||||||
HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
|
Map<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<>();
|
||||||
mapClassMethods(node, mapClassMeths);
|
mapClassMethods(node, mapClassMeths);
|
||||||
|
|
||||||
if (mapClassMeths.isEmpty()) {
|
if (mapClassMeths.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<ClassWrapper> setFound = new HashSet<ClassWrapper>();
|
Set<ClassWrapper> setFound = new HashSet<>();
|
||||||
processClassRec(node, mapClassMeths, setFound);
|
processClassRec(node, mapClassMeths, setFound);
|
||||||
|
|
||||||
if (!setFound.isEmpty()) {
|
if (!setFound.isEmpty()) {
|
||||||
@ -119,29 +74,21 @@ public class ClassReference14Processor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processClassRec(ClassNode node,
|
private static void processClassRec(ClassNode node, Map<ClassWrapper, MethodWrapper> mapClassMeths, Set<? super ClassWrapper> setFound) {
|
||||||
final HashMap<ClassWrapper, MethodWrapper> mapClassMeths,
|
ClassWrapper wrapper = node.getWrapper();
|
||||||
final HashSet<ClassWrapper> setFound) {
|
|
||||||
|
|
||||||
final ClassWrapper wrapper = node.wrapper;
|
|
||||||
|
|
||||||
// search code
|
// search code
|
||||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
for (MethodWrapper meth : wrapper.getMethods()) {
|
||||||
|
|
||||||
RootStatement root = meth.root;
|
RootStatement root = meth.root;
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
|
|
||||||
DirectGraph graph = meth.getOrBuildGraph();
|
DirectGraph graph = meth.getOrBuildGraph();
|
||||||
|
graph.iterateExprents(exprent -> {
|
||||||
graph.iterateExprents(new DirectGraph.ExprentIterator() {
|
for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
|
||||||
public int processExprent(Exprent exprent) {
|
if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
|
||||||
for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
|
setFound.add(ent.getKey());
|
||||||
if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
|
|
||||||
setFound.add(ent.getKey());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +107,7 @@ public class ClassReference14Processor {
|
|||||||
|
|
||||||
String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
|
String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
|
||||||
if (cl != null) {
|
if (cl != null) {
|
||||||
initializers.set(i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
|
initializers.set(i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/'), exprent.bytecode));
|
||||||
setFound.add(ent.getKey());
|
setFound.add(ent.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,10 +120,10 @@ public class ClassReference14Processor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mapClassMethods(ClassNode node, Map<ClassWrapper, MethodWrapper> map) {
|
private static void mapClassMethods(ClassNode node, Map<ClassWrapper, MethodWrapper> map) {
|
||||||
boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
|
boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
|
||||||
|
|
||||||
ClassWrapper wrapper = node.wrapper;
|
ClassWrapper wrapper = node.getWrapper();
|
||||||
|
|
||||||
for (MethodWrapper method : wrapper.getMethods()) {
|
for (MethodWrapper method : wrapper.getMethods()) {
|
||||||
StructMethod mt = method.methodStruct;
|
StructMethod mt = method.methodStruct;
|
||||||
@ -190,14 +137,14 @@ public class ClassReference14Processor {
|
|||||||
CatchStatement cst = (CatchStatement)root.getFirst();
|
CatchStatement cst = (CatchStatement)root.getFirst();
|
||||||
if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
|
if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
|
||||||
cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
|
cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
|
||||||
cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) {
|
cst.getVars().get(0).getVarType().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) {
|
||||||
|
|
||||||
BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
|
BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
|
||||||
BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
|
BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
|
||||||
|
|
||||||
if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
|
if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
|
||||||
if (bodyexprent.equals(body.getExprents().get(0)) &&
|
if (BODY_EXPR.equals(body.getExprents().get(0)) &&
|
||||||
handlerexprent.equals(handler.getExprents().get(0))) {
|
HANDLER_EXPR.equals(handler.getExprents().get(0))) {
|
||||||
map.put(wrapper, method);
|
map.put(wrapper, method);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -213,19 +160,16 @@ public class ClassReference14Processor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
|
private static boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
|
||||||
|
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
|
||||||
for (Exprent expr : exprent.getAllExprents()) {
|
for (Exprent expr : exprent.getAllExprents()) {
|
||||||
String cl = isClass14Invocation(expr, wrapper, meth);
|
String cl = isClass14Invocation(expr, wrapper, meth);
|
||||||
if (cl != null) {
|
if (cl != null) {
|
||||||
exprent.replaceExprent(expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
|
exprent.replaceExprent(expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/'), expr.bytecode));
|
||||||
found = true;
|
found = true;
|
||||||
res = true;
|
res = true;
|
||||||
break;
|
break;
|
||||||
@ -242,18 +186,16 @@ public class ClassReference14Processor {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
|
private static String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
|
||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
||||||
FunctionExprent fexpr = (FunctionExprent)exprent;
|
FunctionExprent fexpr = (FunctionExprent)exprent;
|
||||||
if (fexpr.getFunctype() == FunctionExprent.FUNCTION_IIF) {
|
if (fexpr.getFuncType() == FunctionExprent.FUNCTION_IIF) {
|
||||||
if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
|
if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
|
||||||
FunctionExprent headexpr = (FunctionExprent)fexpr.getLstOperands().get(0);
|
FunctionExprent headexpr = (FunctionExprent)fexpr.getLstOperands().get(0);
|
||||||
if (headexpr.getFunctype() == FunctionExprent.FUNCTION_EQ) {
|
if (headexpr.getFuncType() == FunctionExprent.FUNCTION_EQ) {
|
||||||
if (headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD &&
|
if (headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD &&
|
||||||
headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST &&
|
headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST &&
|
||||||
((ConstExprent)headexpr.getLstOperands().get(1)).getConsttype().equals(VarType.VARTYPE_NULL)) {
|
((ConstExprent)headexpr.getLstOperands().get(1)).getConstType().equals(VarType.VARTYPE_NULL)) {
|
||||||
|
|
||||||
FieldExprent field = (FieldExprent)headexpr.getLstOperands().get(0);
|
FieldExprent field = (FieldExprent)headexpr.getLstOperands().get(0);
|
||||||
ClassNode fieldnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(field.getClassname());
|
ClassNode fieldnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(field.getClassname());
|
||||||
@ -293,4 +235,4 @@ public class ClassReference14Processor {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,10 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
|
import org.jetbrains.java.decompiler.code.Instruction;
|
||||||
|
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
|
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
|
||||||
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
|
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
||||||
@ -27,109 +14,103 @@ import org.jetbrains.java.decompiler.main.rels.LambdaProcessor;
|
|||||||
import org.jetbrains.java.decompiler.main.rels.NestedClassProcessor;
|
import org.jetbrains.java.decompiler.main.rels.NestedClassProcessor;
|
||||||
import org.jetbrains.java.decompiler.main.rels.NestedMemberAccess;
|
import org.jetbrains.java.decompiler.main.rels.NestedMemberAccess;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
|
import org.jetbrains.java.decompiler.struct.attr.StructEnclosingMethodAttribute;
|
||||||
|
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||||
import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute;
|
import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute;
|
||||||
|
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
import org.jetbrains.java.decompiler.util.TextBuffer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public class ClassesProcessor {
|
public class ClassesProcessor implements CodeConstants {
|
||||||
|
|
||||||
public static final int AVERAGE_CLASS_SIZE = 16 * 1024;
|
public static final int AVERAGE_CLASS_SIZE = 16 * 1024;
|
||||||
|
|
||||||
private Map<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
|
private final StructContext context;
|
||||||
|
private final Map<String, ClassNode> mapRootClasses = new HashMap<>();
|
||||||
|
|
||||||
|
private static class Inner {
|
||||||
|
private String simpleName;
|
||||||
|
private int type;
|
||||||
|
private int accessFlags;
|
||||||
|
|
||||||
|
private static boolean equal(Inner o1, Inner o2) {
|
||||||
|
return o1.type == o2.type && o1.accessFlags == o2.accessFlags && InterpreterUtil.equalObjects(o1.simpleName, o2.simpleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ClassesProcessor(StructContext context) {
|
public ClassesProcessor(StructContext context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
HashMap<String, Object[]> mapInnerClasses = new HashMap<String, Object[]>();
|
public void loadClasses(IIdentifierRenamer renamer) {
|
||||||
HashMap<String, HashSet<String>> mapNestedClassReferences = new HashMap<String, HashSet<String>>();
|
Map<String, Inner> mapInnerClasses = new HashMap<>();
|
||||||
HashMap<String, HashSet<String>> mapEnclosingClassReferences = new HashMap<String, HashSet<String>>();
|
Map<String, Set<String>> mapNestedClassReferences = new HashMap<>();
|
||||||
HashMap<String, String> mapNewSimpleNames = new HashMap<String, String>();
|
Map<String, Set<String>> mapEnclosingClassReferences = new HashMap<>();
|
||||||
|
Map<String, String> mapNewSimpleNames = new HashMap<>();
|
||||||
|
|
||||||
boolean bDecompileInner = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_INNER);
|
boolean bDecompileInner = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_INNER);
|
||||||
|
boolean verifyAnonymousClasses = DecompilerContext.getOption(IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES);
|
||||||
|
|
||||||
// create class nodes
|
// create class nodes
|
||||||
for (StructClass cl : context.getClasses().values()) {
|
for (StructClass cl : context.getClasses().values()) {
|
||||||
if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
|
if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
|
||||||
|
|
||||||
if (bDecompileInner) {
|
if (bDecompileInner) {
|
||||||
StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses");
|
StructInnerClassesAttribute inner = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES);
|
||||||
|
|
||||||
if (inner != null) {
|
if (inner != null) {
|
||||||
|
for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) {
|
||||||
for (int i = 0; i < inner.getClassEntries().size(); i++) {
|
String innerName = entry.innerName;
|
||||||
|
|
||||||
int[] entry = inner.getClassEntries().get(i);
|
|
||||||
String[] strentry = inner.getStringEntries().get(i);
|
|
||||||
|
|
||||||
Object[] arr = new Object[4]; // arr[0] not used
|
|
||||||
|
|
||||||
String innername = strentry[0];
|
|
||||||
|
|
||||||
// nested class type
|
|
||||||
arr[2] = entry[1] == 0 ? (entry[2] == 0 ? ClassNode.CLASS_ANONYMOUS : ClassNode.CLASS_LOCAL) : ClassNode.CLASS_MEMBER;
|
|
||||||
|
|
||||||
// original simple name
|
// original simple name
|
||||||
String simpleName = strentry[2];
|
String simpleName = entry.simpleName;
|
||||||
String savedName = mapNewSimpleNames.get(innername);
|
String savedName = mapNewSimpleNames.get(innerName);
|
||||||
|
|
||||||
if (savedName != null) {
|
if (savedName != null) {
|
||||||
simpleName = savedName;
|
simpleName = savedName;
|
||||||
}
|
}
|
||||||
else if (simpleName != null && DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
|
else if (simpleName != null &&
|
||||||
IIdentifierRenamer renamer = DecompilerContext.getPoolInterceptor().getHelper();
|
renamer != null &&
|
||||||
if (renamer.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, simpleName, null, null)) {
|
renamer.toBeRenamed(IIdentifierRenamer.Type.ELEMENT_CLASS, simpleName, null, null)) {
|
||||||
simpleName = renamer.getNextClassname(innername, simpleName);
|
simpleName = renamer.getNextClassName(innerName, simpleName);
|
||||||
mapNewSimpleNames.put(innername, simpleName);
|
mapNewSimpleNames.put(innerName, simpleName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arr[1] = simpleName;
|
Inner rec = new Inner();
|
||||||
|
rec.simpleName = simpleName;
|
||||||
// original access flags
|
rec.type = entry.simpleNameIdx == 0 ? ClassNode.CLASS_ANONYMOUS : entry.outerNameIdx == 0 ? ClassNode.CLASS_LOCAL : ClassNode.CLASS_MEMBER;
|
||||||
arr[3] = entry[3];
|
rec.accessFlags = entry.accessFlags;
|
||||||
|
|
||||||
// enclosing class
|
// enclosing class
|
||||||
String enclClassName;
|
String enclClassName = entry.outerNameIdx != 0 ? entry.enclosingName : cl.qualifiedName;
|
||||||
if (entry[1] != 0) {
|
if (enclClassName == null || innerName.equals(enclClassName)) {
|
||||||
enclClassName = strentry[1];
|
continue; // invalid name or self reference
|
||||||
}
|
}
|
||||||
else {
|
if (rec.type == ClassNode.CLASS_MEMBER && !innerName.equals(enclClassName + '$' + entry.simpleName)) {
|
||||||
enclClassName = cl.qualifiedName;
|
continue; // not a real inner class
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!innername.equals(enclClassName)) { // self reference
|
StructClass enclosingClass = context.getClasses().get(enclClassName);
|
||||||
StructClass enclosing_class = context.getClasses().get(enclClassName);
|
if (enclosingClass != null && enclosingClass.isOwn()) { // own classes only
|
||||||
if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only
|
Inner existingRec = mapInnerClasses.get(innerName);
|
||||||
|
if (existingRec == null) {
|
||||||
Object[] arrold = mapInnerClasses.get(innername);
|
mapInnerClasses.put(innerName, rec);
|
||||||
if (arrold == null) {
|
|
||||||
mapInnerClasses.put(innername, arr);
|
|
||||||
}
|
|
||||||
else if (!InterpreterUtil.equalObjectArrays(arrold, arr)) {
|
|
||||||
String message = "Inconsistent inner class entries for " + innername + "!";
|
|
||||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reference to the nested class
|
|
||||||
HashSet<String> set = mapNestedClassReferences.get(enclClassName);
|
|
||||||
if (set == null) {
|
|
||||||
mapNestedClassReferences.put(enclClassName, set = new HashSet<String>());
|
|
||||||
}
|
|
||||||
set.add(innername);
|
|
||||||
|
|
||||||
// reference to the enclosing class
|
|
||||||
set = mapEnclosingClassReferences.get(innername);
|
|
||||||
if (set == null) {
|
|
||||||
mapEnclosingClassReferences.put(innername, set = new HashSet<String>());
|
|
||||||
}
|
|
||||||
set.add(enclClassName);
|
|
||||||
}
|
}
|
||||||
|
else if (!Inner.equal(existingRec, rec)) {
|
||||||
|
String message = "Inconsistent inner class entries for " + innerName + "!";
|
||||||
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reference to the nested class
|
||||||
|
mapNestedClassReferences.computeIfAbsent(enclClassName, k -> new HashSet<>()).add(innerName);
|
||||||
|
// reference to the enclosing class
|
||||||
|
mapEnclosingClassReferences.computeIfAbsent(innerName, k -> new HashSet<>()).add(enclClassName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,30 +123,32 @@ public class ClassesProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bDecompileInner) {
|
if (bDecompileInner) {
|
||||||
|
|
||||||
// connect nested classes
|
// connect nested classes
|
||||||
for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) {
|
for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) {
|
||||||
// root class?
|
// root class?
|
||||||
if (!mapInnerClasses.containsKey(ent.getKey())) {
|
if (!mapInnerClasses.containsKey(ent.getKey())) {
|
||||||
|
Set<String> setVisited = new HashSet<>();
|
||||||
HashSet<String> setVisited = new HashSet<String>();
|
LinkedList<String> stack = new LinkedList<>();
|
||||||
LinkedList<String> stack = new LinkedList<String>();
|
|
||||||
|
|
||||||
stack.add(ent.getKey());
|
stack.add(ent.getKey());
|
||||||
setVisited.add(ent.getKey());
|
setVisited.add(ent.getKey());
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
|
|
||||||
String superClass = stack.removeFirst();
|
String superClass = stack.removeFirst();
|
||||||
ClassNode supernode = mapRootClasses.get(superClass);
|
ClassNode superNode = mapRootClasses.get(superClass);
|
||||||
|
|
||||||
HashSet<String> setNestedClasses = mapNestedClassReferences.get(superClass);
|
Set<String> setNestedClasses = mapNestedClassReferences.get(superClass);
|
||||||
if (setNestedClasses != null) {
|
if (setNestedClasses != null) {
|
||||||
|
StructClass scl = superNode.classStruct;
|
||||||
|
StructInnerClassesAttribute inner = scl.getAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES);
|
||||||
|
|
||||||
StructClass scl = supernode.classStruct;
|
if (inner == null || inner.getEntries().isEmpty()) {
|
||||||
StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses");
|
DecompilerContext.getLogger().writeMessage(superClass + " does not contain inner classes!", IFernflowerLogger.Severity.WARN);
|
||||||
for (int i = 0; i < inner.getStringEntries().size(); i++) {
|
continue;
|
||||||
String nestedClass = inner.getStringEntries().get(i)[0];
|
}
|
||||||
|
|
||||||
|
for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) {
|
||||||
|
String nestedClass = entry.innerName;
|
||||||
if (!setNestedClasses.contains(nestedClass)) {
|
if (!setNestedClasses.contains(nestedClass)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -174,52 +157,49 @@ public class ClassesProcessor {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassNode nestednode = mapRootClasses.get(nestedClass);
|
ClassNode nestedNode = mapRootClasses.get(nestedClass);
|
||||||
if (nestednode == null) {
|
if (nestedNode == null) {
|
||||||
DecompilerContext.getLogger().writeMessage("Nested class " + nestedClass + " missing!", IFernflowerLogger.Severity.WARN);
|
DecompilerContext.getLogger().writeMessage("Nested class " + nestedClass + " missing!", IFernflowerLogger.Severity.WARN);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object[] arr = mapInnerClasses.get(nestedClass);
|
Inner rec = mapInnerClasses.get(nestedClass);
|
||||||
|
|
||||||
//if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
|
//if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
|
||||||
// FIXME: check for consistent naming
|
// FIXME: check for consistent naming
|
||||||
//}
|
//}
|
||||||
|
|
||||||
nestednode.type = (Integer)arr[2];
|
nestedNode.simpleName = rec.simpleName;
|
||||||
nestednode.simpleName = (String)arr[1];
|
nestedNode.type = rec.type;
|
||||||
nestednode.access = (Integer)arr[3];
|
nestedNode.access = rec.accessFlags;
|
||||||
|
|
||||||
if (nestednode.type == ClassNode.CLASS_ANONYMOUS) {
|
// sanity checks of the class supposed to be anonymous
|
||||||
StructClass cl = nestednode.classStruct;
|
if (verifyAnonymousClasses && nestedNode.type == ClassNode.CLASS_ANONYMOUS && !isAnonymous(nestedNode.classStruct, scl)) {
|
||||||
|
nestedNode.type = ClassNode.CLASS_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
// remove static if anonymous class
|
if (nestedNode.type == ClassNode.CLASS_ANONYMOUS) {
|
||||||
// a common compiler bug
|
StructClass cl = nestedNode.classStruct;
|
||||||
nestednode.access &= ~CodeConstants.ACC_STATIC;
|
// remove static if anonymous class (a common compiler bug)
|
||||||
|
nestedNode.access &= ~CodeConstants.ACC_STATIC;
|
||||||
|
|
||||||
int[] interfaces = cl.getInterfaces();
|
int[] interfaces = cl.getInterfaces();
|
||||||
|
|
||||||
if (interfaces.length > 0) {
|
if (interfaces.length > 0) {
|
||||||
if (interfaces.length > 1) {
|
nestedNode.anonymousClassType = new VarType(cl.getInterface(0), true);
|
||||||
String message = "Inconsistent anonymous class definition: " + cl.qualifiedName;
|
|
||||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
|
||||||
}
|
|
||||||
nestednode.anonymousClassType = new VarType(cl.getInterface(0), true);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nestednode.anonymousClassType = new VarType(cl.superClass.getString(), true);
|
nestedNode.anonymousClassType = new VarType(cl.superClass.getString(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (nestednode.type == ClassNode.CLASS_LOCAL) {
|
else if (nestedNode.type == ClassNode.CLASS_LOCAL) {
|
||||||
// only abstract and final are permitted
|
// only abstract and final are permitted (a common compiler bug)
|
||||||
// a common compiler bug
|
nestedNode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
|
||||||
nestednode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
supernode.nested.add(nestednode);
|
superNode.nested.add(nestedNode);
|
||||||
nestednode.parent = supernode;
|
nestedNode.parent = superNode;
|
||||||
|
|
||||||
nestednode.enclosingClasses.addAll(mapEnclosingClassReferences.get(nestedClass));
|
nestedNode.enclosingClasses.addAll(mapEnclosingClassReferences.get(nestedClass));
|
||||||
|
|
||||||
stack.add(nestedClass);
|
stack.add(nestedClass);
|
||||||
}
|
}
|
||||||
@ -230,64 +210,158 @@ public class ClassesProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isAnonymous(StructClass cl, StructClass enclosingCl) {
|
||||||
|
// checking super class and interfaces
|
||||||
|
int[] interfaces = cl.getInterfaces();
|
||||||
|
if (interfaces.length > 0) {
|
||||||
|
boolean hasNonTrivialSuperClass = cl.superClass != null && !VarType.VARTYPE_OBJECT.equals(new VarType(cl.superClass.getString(), true));
|
||||||
|
if (hasNonTrivialSuperClass || interfaces.length > 1) { // can't have multiple 'sources'
|
||||||
|
String message = "Inconsistent anonymous class definition: '" + cl.qualifiedName + "'. Multiple interfaces and/or super class defined.";
|
||||||
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cl.superClass == null) { // neither interface nor super class defined
|
||||||
|
String message = "Inconsistent anonymous class definition: '" + cl.qualifiedName + "'. Neither interface nor super class defined.";
|
||||||
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: check constructors
|
||||||
|
// FIXME: check enclosing class/method
|
||||||
|
|
||||||
|
ConstantPool pool = enclosingCl.getPool();
|
||||||
|
|
||||||
|
int refCounter = 0;
|
||||||
|
boolean refNotNew = false;
|
||||||
|
|
||||||
|
StructEnclosingMethodAttribute attribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_ENCLOSING_METHOD);
|
||||||
|
String enclosingMethod = attribute != null ? attribute.getMethodName() : null;
|
||||||
|
|
||||||
|
// checking references in the enclosing class
|
||||||
|
for (StructMethod mt : enclosingCl.getMethods()) {
|
||||||
|
if (enclosingMethod != null && !enclosingMethod.equals(mt.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mt.expandData(enclosingCl);
|
||||||
|
|
||||||
|
InstructionSequence seq = mt.getInstructionSequence();
|
||||||
|
if (seq != null) {
|
||||||
|
int len = seq.length();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
Instruction instr = seq.getInstr(i);
|
||||||
|
switch (instr.opcode) {
|
||||||
|
case opc_checkcast:
|
||||||
|
case opc_instanceof:
|
||||||
|
if (cl.qualifiedName.equals(pool.getPrimitiveConstant(instr.operand(0)).getString())) {
|
||||||
|
refCounter++;
|
||||||
|
refNotNew = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case opc_new:
|
||||||
|
case opc_anewarray:
|
||||||
|
case opc_multianewarray:
|
||||||
|
if (cl.qualifiedName.equals(pool.getPrimitiveConstant(instr.operand(0)).getString())) {
|
||||||
|
refCounter++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case opc_getstatic:
|
||||||
|
case opc_putstatic:
|
||||||
|
if (cl.qualifiedName.equals(pool.getLinkConstant(instr.operand(0)).classname)) {
|
||||||
|
refCounter++;
|
||||||
|
refNotNew = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mt.releaseResources();
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
String message = "Could not read method while checking anonymous class definition: '" + enclosingCl.qualifiedName + "', '" +
|
||||||
|
InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()) + "'";
|
||||||
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refCounter > 1 || refNotNew) {
|
||||||
|
String message = "Inconsistent references to the class '" + cl.qualifiedName + "' which is supposed to be anonymous";
|
||||||
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void writeClass(StructClass cl, TextBuffer buffer) throws IOException {
|
public void writeClass(StructClass cl, TextBuffer buffer) throws IOException {
|
||||||
ClassNode root = mapRootClasses.get(cl.qualifiedName);
|
ClassNode root = mapRootClasses.get(cl.qualifiedName);
|
||||||
if (root.type != ClassNode.CLASS_ROOT) {
|
if (root.type != ClassNode.CLASS_ROOT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean packageInfo = cl.isSynthetic() && "package-info".equals(root.simpleName);
|
||||||
|
boolean moduleInfo = cl.hasModifier(CodeConstants.ACC_MODULE) && cl.hasAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
|
||||||
|
|
||||||
DecompilerContext.getLogger().startReadingClass(cl.qualifiedName);
|
DecompilerContext.getLogger().startReadingClass(cl.qualifiedName);
|
||||||
try {
|
try {
|
||||||
ImportCollector importCollector = new ImportCollector(root);
|
ImportCollector importCollector = new ImportCollector(root);
|
||||||
DecompilerContext.setImportCollector(importCollector);
|
DecompilerContext.startClass(importCollector);
|
||||||
DecompilerContext.setCounterContainer(new CounterContainer());
|
|
||||||
DecompilerContext.setBytecodeSourceMapper(new BytecodeSourceMapper());
|
|
||||||
|
|
||||||
new LambdaProcessor().processClass(root);
|
if (packageInfo) {
|
||||||
|
ClassWriter.packageInfoToJava(cl, buffer);
|
||||||
|
|
||||||
// add simple class names to implicit import
|
importCollector.writeImports(buffer, false);
|
||||||
addClassnameToImport(root, importCollector);
|
|
||||||
|
|
||||||
// build wrappers for all nested classes (that's where actual processing takes place)
|
|
||||||
initWrappers(root);
|
|
||||||
|
|
||||||
new NestedClassProcessor().processClass(root, root);
|
|
||||||
|
|
||||||
new NestedMemberAccess().propagateMemberAccess(root);
|
|
||||||
|
|
||||||
TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
|
|
||||||
new ClassWriter().classToJava(root, classBuffer, 0);
|
|
||||||
|
|
||||||
String lineSeparator = DecompilerContext.getNewLineSeparator();
|
|
||||||
int total_offset_lines = 0;
|
|
||||||
|
|
||||||
int index = cl.qualifiedName.lastIndexOf("/");
|
|
||||||
if (index >= 0) {
|
|
||||||
total_offset_lines+=2;
|
|
||||||
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
|
|
||||||
|
|
||||||
buffer.append("package ");
|
|
||||||
buffer.append(packageName);
|
|
||||||
buffer.append(";");
|
|
||||||
buffer.append(lineSeparator);
|
|
||||||
buffer.append(lineSeparator);
|
|
||||||
}
|
}
|
||||||
|
else if (moduleInfo) {
|
||||||
|
TextBuffer moduleBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
|
||||||
|
ClassWriter.moduleInfoToJava(cl, moduleBuffer);
|
||||||
|
|
||||||
int import_lines_written = importCollector.writeImports(buffer);
|
importCollector.writeImports(buffer, true);
|
||||||
if (import_lines_written > 0) {
|
|
||||||
buffer.append(lineSeparator);
|
buffer.append(moduleBuffer);
|
||||||
total_offset_lines += import_lines_written + 1;
|
|
||||||
}
|
}
|
||||||
//buffer.append(lineSeparator);
|
else {
|
||||||
|
new LambdaProcessor().processClass(root);
|
||||||
|
|
||||||
buffer.append(classBuffer);
|
// add simple class names to implicit import
|
||||||
|
addClassNameToImport(root, importCollector);
|
||||||
|
|
||||||
if(DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {
|
// build wrappers for all nested classes (that's where actual processing takes place)
|
||||||
BytecodeSourceMapper mapper = DecompilerContext.getBytecodeSourceMapper();
|
initWrappers(root);
|
||||||
mapper.addTotalOffset(total_offset_lines);
|
|
||||||
|
|
||||||
buffer.append(lineSeparator);
|
new NestedClassProcessor().processClass(root, root);
|
||||||
mapper.dumpMapping(buffer);
|
|
||||||
|
new NestedMemberAccess().propagateMemberAccess(root);
|
||||||
|
|
||||||
|
TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
|
||||||
|
new ClassWriter().classToJava(root, classBuffer, 0, null);
|
||||||
|
|
||||||
|
int index = cl.qualifiedName.lastIndexOf('/');
|
||||||
|
if (index >= 0) {
|
||||||
|
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
|
||||||
|
buffer.append("package ").append(packageName).append(';').appendLineSeparator().appendLineSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
importCollector.writeImports(buffer, true);
|
||||||
|
|
||||||
|
int offsetLines = buffer.countLines();
|
||||||
|
|
||||||
|
buffer.append(classBuffer);
|
||||||
|
|
||||||
|
if (DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {
|
||||||
|
BytecodeSourceMapper mapper = DecompilerContext.getBytecodeSourceMapper();
|
||||||
|
mapper.addTotalOffset(offsetLines);
|
||||||
|
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_ORIGINAL_LINES)) {
|
||||||
|
buffer.dumpOriginalLineNumbers(mapper.getOriginalLinesMapping());
|
||||||
|
}
|
||||||
|
if (DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE)) {
|
||||||
|
buffer.appendLineSeparator();
|
||||||
|
mapper.dumpMapping(buffer, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@ -296,8 +370,7 @@ public class ClassesProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initWrappers(ClassNode node) throws IOException {
|
private static void initWrappers(ClassNode node) {
|
||||||
|
|
||||||
if (node.type == ClassNode.CLASS_LAMBDA) {
|
if (node.type == ClassNode.CLASS_LAMBDA) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -312,19 +385,17 @@ public class ClassesProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addClassnameToImport(ClassNode node, ImportCollector imp) {
|
private static void addClassNameToImport(ClassNode node, ImportCollector imp) {
|
||||||
|
|
||||||
if (node.simpleName != null && node.simpleName.length() > 0) {
|
if (node.simpleName != null && node.simpleName.length() > 0) {
|
||||||
imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false);
|
imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ClassNode nd : node.nested) {
|
for (ClassNode nd : node.nested) {
|
||||||
addClassnameToImport(nd, imp);
|
addClassNameToImport(nd, imp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void destroyWrappers(ClassNode node) {
|
private static void destroyWrappers(ClassNode node) {
|
||||||
|
|
||||||
node.wrapper = null;
|
node.wrapper = null;
|
||||||
node.classStruct.releaseResources();
|
node.classStruct.releaseResources();
|
||||||
|
|
||||||
@ -339,7 +410,6 @@ public class ClassesProcessor {
|
|||||||
|
|
||||||
|
|
||||||
public static class ClassNode {
|
public static class ClassNode {
|
||||||
|
|
||||||
public static final int CLASS_ROOT = 0;
|
public static final int CLASS_ROOT = 0;
|
||||||
public static final int CLASS_MEMBER = 1;
|
public static final int CLASS_MEMBER = 1;
|
||||||
public static final int CLASS_ANONYMOUS = 2;
|
public static final int CLASS_ANONYMOUS = 2;
|
||||||
@ -347,30 +417,18 @@ public class ClassesProcessor {
|
|||||||
public static final int CLASS_LAMBDA = 8;
|
public static final int CLASS_LAMBDA = 8;
|
||||||
|
|
||||||
public int type;
|
public int type;
|
||||||
|
|
||||||
public int access;
|
public int access;
|
||||||
|
|
||||||
public String simpleName;
|
public String simpleName;
|
||||||
|
public final StructClass classStruct;
|
||||||
public StructClass classStruct;
|
private ClassWrapper wrapper;
|
||||||
|
|
||||||
public ClassWrapper wrapper;
|
|
||||||
|
|
||||||
public String enclosingMethod;
|
public String enclosingMethod;
|
||||||
|
|
||||||
public InvocationExprent superInvocation;
|
public InvocationExprent superInvocation;
|
||||||
|
public final Map<String, VarVersionPair> mapFieldsToVars = new HashMap<>();
|
||||||
public HashMap<String, VarVersionPaar> mapFieldsToVars = new HashMap<String, VarVersionPaar>();
|
|
||||||
|
|
||||||
public VarType anonymousClassType;
|
public VarType anonymousClassType;
|
||||||
|
public final List<ClassNode> nested = new ArrayList<>();
|
||||||
public List<ClassNode> nested = new ArrayList<ClassNode>();
|
public final Set<String> enclosingClasses = new HashSet<>();
|
||||||
|
|
||||||
public Set<String> enclosingClasses = new HashSet<String>();
|
|
||||||
|
|
||||||
public ClassNode parent;
|
public ClassNode parent;
|
||||||
|
public LambdaInformation lambdaInformation;
|
||||||
public LambdaInformation lambda_information;
|
|
||||||
|
|
||||||
public ClassNode(String content_class_name,
|
public ClassNode(String content_class_name,
|
||||||
String content_method_name,
|
String content_method_name,
|
||||||
@ -383,19 +441,18 @@ public class ClassesProcessor {
|
|||||||
this.type = CLASS_LAMBDA;
|
this.type = CLASS_LAMBDA;
|
||||||
this.classStruct = classStruct; // 'parent' class containing the static function
|
this.classStruct = classStruct; // 'parent' class containing the static function
|
||||||
|
|
||||||
lambda_information = new LambdaInformation();
|
lambdaInformation = new LambdaInformation();
|
||||||
|
|
||||||
lambda_information.class_name = lambda_class_name;
|
lambdaInformation.method_name = lambda_method_name;
|
||||||
lambda_information.method_name = lambda_method_name;
|
lambdaInformation.method_descriptor = lambda_method_descriptor;
|
||||||
lambda_information.method_descriptor = lambda_method_descriptor;
|
|
||||||
|
|
||||||
lambda_information.content_class_name = content_class_name;
|
lambdaInformation.content_class_name = content_class_name;
|
||||||
lambda_information.content_method_name = content_method_name;
|
lambdaInformation.content_method_name = content_method_name;
|
||||||
lambda_information.content_method_descriptor = content_method_descriptor;
|
lambdaInformation.content_method_descriptor = content_method_descriptor;
|
||||||
lambda_information.content_method_invocation_type = content_method_invocation_type;
|
lambdaInformation.content_method_invocation_type = content_method_invocation_type;
|
||||||
|
|
||||||
lambda_information.content_method_key =
|
lambdaInformation.content_method_key =
|
||||||
InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
|
InterpreterUtil.makeUniqueKey(lambdaInformation.content_method_name, lambdaInformation.content_method_descriptor);
|
||||||
|
|
||||||
anonymousClassType = new VarType(lambda_class_name, true);
|
anonymousClassType = new VarType(lambda_class_name, true);
|
||||||
|
|
||||||
@ -405,9 +462,9 @@ public class ClassesProcessor {
|
|||||||
is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference
|
is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference
|
||||||
}
|
}
|
||||||
|
|
||||||
lambda_information.is_method_reference = is_method_reference;
|
lambdaInformation.is_method_reference = is_method_reference;
|
||||||
lambda_information.is_content_method_static =
|
lambdaInformation.is_content_method_static =
|
||||||
(lambda_information.content_method_invocation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
|
(lambdaInformation.content_method_invocation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassNode(int type, StructClass classStruct) {
|
public ClassNode(int type, StructClass classStruct) {
|
||||||
@ -426,8 +483,15 @@ public class ClassesProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClassWrapper getWrapper() {
|
||||||
|
ClassNode node = this;
|
||||||
|
while (node.type == CLASS_LAMBDA) {
|
||||||
|
node = node.parent;
|
||||||
|
}
|
||||||
|
return node.wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
public static class LambdaInformation {
|
public static class LambdaInformation {
|
||||||
public String class_name;
|
|
||||||
public String method_name;
|
public String method_name;
|
||||||
public String method_descriptor;
|
public String method_descriptor;
|
||||||
|
|
||||||
@ -435,11 +499,10 @@ public class ClassesProcessor {
|
|||||||
public String content_method_name;
|
public String content_method_name;
|
||||||
public String content_method_descriptor;
|
public String content_method_descriptor;
|
||||||
public int content_method_invocation_type; // values from CONSTANT_MethodHandle_REF_*
|
public int content_method_invocation_type; // values from CONSTANT_MethodHandle_REF_*
|
||||||
|
|
||||||
public String content_method_key;
|
public String content_method_key;
|
||||||
|
|
||||||
public boolean is_method_reference;
|
public boolean is_method_reference;
|
||||||
public boolean is_content_method_static;
|
public boolean is_content_method_static;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,64 +1,57 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
|
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
|
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
|
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
||||||
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
|
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class DecompilerContext {
|
public class DecompilerContext {
|
||||||
public static final String CURRENT_CLASS = "CURRENT_CLASS";
|
public static final String CURRENT_CLASS = "CURRENT_CLASS";
|
||||||
|
public static final String CURRENT_CLASS_WRAPPER = "CURRENT_CLASS_WRAPPER";
|
||||||
public static final String CURRENT_CLASS_NODE = "CURRENT_CLASS_NODE";
|
public static final String CURRENT_CLASS_NODE = "CURRENT_CLASS_NODE";
|
||||||
public static final String CURRENT_METHOD = "CURRENT_METHOD";
|
|
||||||
public static final String CURRENT_METHOD_DESCRIPTOR = "CURRENT_METHOD_DESCRIPTOR";
|
|
||||||
public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
|
public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
|
||||||
public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR";
|
|
||||||
|
|
||||||
private static ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<DecompilerContext>();
|
|
||||||
|
|
||||||
private final Map<String, Object> properties;
|
private final Map<String, Object> properties;
|
||||||
private StructContext structContext;
|
private final IFernflowerLogger logger;
|
||||||
|
private final StructContext structContext;
|
||||||
|
private final ClassesProcessor classProcessor;
|
||||||
|
private final PoolInterceptor poolInterceptor;
|
||||||
private ImportCollector importCollector;
|
private ImportCollector importCollector;
|
||||||
private VarNamesCollector varNamescollector;
|
private VarProcessor varProcessor;
|
||||||
private CounterContainer counterContainer;
|
private CounterContainer counterContainer;
|
||||||
private ClassesProcessor classProcessor;
|
|
||||||
private PoolInterceptor poolInterceptor;
|
|
||||||
private IFernflowerLogger logger;
|
|
||||||
private BytecodeSourceMapper bytecodeSourceMapper;
|
private BytecodeSourceMapper bytecodeSourceMapper;
|
||||||
|
|
||||||
private DecompilerContext(Map<String, Object> properties) {
|
public DecompilerContext(Map<String, Object> properties,
|
||||||
|
IFernflowerLogger logger,
|
||||||
|
StructContext structContext,
|
||||||
|
ClassesProcessor classProcessor,
|
||||||
|
PoolInterceptor interceptor) {
|
||||||
|
Objects.requireNonNull(properties);
|
||||||
|
Objects.requireNonNull(logger);
|
||||||
|
Objects.requireNonNull(structContext);
|
||||||
|
Objects.requireNonNull(classProcessor);
|
||||||
|
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
this.logger = logger;
|
||||||
|
this.structContext = structContext;
|
||||||
|
this.classProcessor = classProcessor;
|
||||||
|
this.poolInterceptor = interceptor;
|
||||||
|
this.counterContainer = new CounterContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initContext(Map<String, Object> propertiesCustom) {
|
// *****************************************************************************
|
||||||
Map<String, Object> properties = new HashMap<String, Object>(IFernflowerPreferences.DEFAULTS);
|
// context setup and update
|
||||||
if (propertiesCustom != null) {
|
// *****************************************************************************
|
||||||
properties.putAll(propertiesCustom);
|
|
||||||
}
|
private static final ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<>();
|
||||||
currentContext.set(new DecompilerContext(properties));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DecompilerContext getCurrentContext() {
|
public static DecompilerContext getCurrentContext() {
|
||||||
return currentContext.get();
|
return currentContext.get();
|
||||||
@ -68,93 +61,69 @@ public class DecompilerContext {
|
|||||||
currentContext.set(context);
|
currentContext.set(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getProperty(String key) {
|
|
||||||
return getCurrentContext().properties.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setProperty(String key, Object value) {
|
public static void setProperty(String key, Object value) {
|
||||||
getCurrentContext().properties.put(key, value);
|
getCurrentContext().properties.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void startClass(ImportCollector importCollector) {
|
||||||
|
DecompilerContext context = getCurrentContext();
|
||||||
|
context.importCollector = importCollector;
|
||||||
|
context.counterContainer = new CounterContainer();
|
||||||
|
context.bytecodeSourceMapper = new BytecodeSourceMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startMethod(VarProcessor varProcessor) {
|
||||||
|
DecompilerContext context = getCurrentContext();
|
||||||
|
context.varProcessor = varProcessor;
|
||||||
|
context.counterContainer = new CounterContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
// context access
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
public static Object getProperty(String key) {
|
||||||
|
return getCurrentContext().properties.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean getOption(String key) {
|
public static boolean getOption(String key) {
|
||||||
return "1".equals(getCurrentContext().properties.get(key));
|
return "1".equals(getProperty(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImportCollector getImportCollector() {
|
public static String getNewLineSeparator() {
|
||||||
return getCurrentContext().importCollector;
|
return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
|
||||||
}
|
IFernflowerPreferences.LINE_SEPARATOR_UNX : IFernflowerPreferences.LINE_SEPARATOR_WIN;
|
||||||
|
|
||||||
public static void setImportCollector(ImportCollector importCollector) {
|
|
||||||
getCurrentContext().importCollector = importCollector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VarNamesCollector getVarNamesCollector() {
|
|
||||||
return getCurrentContext().varNamescollector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setVarNamesCollector(VarNamesCollector varNamesCollector) {
|
|
||||||
getCurrentContext().varNamescollector = varNamesCollector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StructContext getStructContext() {
|
|
||||||
return getCurrentContext().structContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setStructContext(StructContext structContext) {
|
|
||||||
getCurrentContext().structContext = structContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CounterContainer getCounterContainer() {
|
|
||||||
return getCurrentContext().counterContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setCounterContainer(CounterContainer counterContainer) {
|
|
||||||
getCurrentContext().counterContainer = counterContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ClassesProcessor getClassProcessor() {
|
|
||||||
return getCurrentContext().classProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setClassProcessor(ClassesProcessor classProcessor) {
|
|
||||||
getCurrentContext().classProcessor = classProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PoolInterceptor getPoolInterceptor() {
|
|
||||||
return getCurrentContext().poolInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setPoolInterceptor(PoolInterceptor poolinterceptor) {
|
|
||||||
getCurrentContext().poolInterceptor = poolinterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BytecodeSourceMapper getBytecodeSourceMapper() {
|
|
||||||
return getCurrentContext().bytecodeSourceMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setBytecodeSourceMapper(BytecodeSourceMapper bytecodeSourceMapper) {
|
|
||||||
getCurrentContext().bytecodeSourceMapper = bytecodeSourceMapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IFernflowerLogger getLogger() {
|
public static IFernflowerLogger getLogger() {
|
||||||
return getCurrentContext().logger;
|
return getCurrentContext().logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setLogger(IFernflowerLogger logger) {
|
public static StructContext getStructContext() {
|
||||||
if (logger != null) {
|
return getCurrentContext().structContext;
|
||||||
String level = (String)getProperty(IFernflowerPreferences.LOG_LEVEL);
|
|
||||||
if (level != null) {
|
|
||||||
try {
|
|
||||||
logger.setSeverity(IFernflowerLogger.Severity.valueOf(level.toUpperCase(Locale.US)));
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException ignore) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getCurrentContext().logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getNewLineSeparator() {
|
public static ClassesProcessor getClassProcessor() {
|
||||||
return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
|
return getCurrentContext().classProcessor;
|
||||||
IFernflowerPreferences.LINE_SEPARATOR_LIN : IFernflowerPreferences.LINE_SEPARATOR_WIN;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static PoolInterceptor getPoolInterceptor() {
|
||||||
|
return getCurrentContext().poolInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImportCollector getImportCollector() {
|
||||||
|
return getCurrentContext().importCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VarProcessor getVarProcessor() {
|
||||||
|
return getCurrentContext().varProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CounterContainer getCounterContainer() {
|
||||||
|
return getCurrentContext().counterContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BytecodeSourceMapper getBytecodeSourceMapper() {
|
||||||
|
return getCurrentContext().bytecodeSourceMapper;
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +1,19 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
|
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
|
||||||
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
|
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statements;
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructField;
|
import org.jetbrains.java.decompiler.struct.StructField;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
|
||||||
public class EnumProcessor {
|
public final class EnumProcessor {
|
||||||
|
|
||||||
public static void clearEnum(ClassWrapper wrapper) {
|
public static void clearEnum(ClassWrapper wrapper) {
|
||||||
StructClass cl = wrapper.getClassStruct();
|
StructClass cl = wrapper.getClassStruct();
|
||||||
|
|
||||||
@ -48,13 +33,13 @@ public class EnumProcessor {
|
|||||||
wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, descriptor));
|
wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, descriptor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ("<init>".equals(name)) {
|
else if (CodeConstants.INIT_NAME.equals(name)) {
|
||||||
Statement firstData = findFirstData(method.root);
|
Statement firstData = Statements.findFirstData(method.root);
|
||||||
if (firstData != null && !firstData.getExprents().isEmpty()) {
|
if (firstData != null && !firstData.getExprents().isEmpty()) {
|
||||||
Exprent exprent = firstData.getExprents().get(0);
|
Exprent exprent = firstData.getExprents().get(0);
|
||||||
if (exprent.type == Exprent.EXPRENT_INVOCATION) {
|
if (exprent.type == Exprent.EXPRENT_INVOCATION) {
|
||||||
InvocationExprent invexpr = (InvocationExprent)exprent;
|
InvocationExprent invExpr = (InvocationExprent)exprent;
|
||||||
if (isInvocationSuperConstructor(invexpr, method, wrapper)) {
|
if (Statements.isInvocationInitConstructor(invExpr, method, wrapper, false)) {
|
||||||
firstData.getExprents().remove(0);
|
firstData.getExprents().remove(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,49 +55,4 @@ public class EnumProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// FIXME: move to a util class (see also InitializerProcessor)
|
|
||||||
private static Statement findFirstData(Statement stat) {
|
|
||||||
|
|
||||||
if (stat.getExprents() != null) {
|
|
||||||
return stat;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (stat.isLabeled()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (stat.type) {
|
|
||||||
case Statement.TYPE_SEQUENCE:
|
|
||||||
case Statement.TYPE_IF:
|
|
||||||
case Statement.TYPE_ROOT:
|
|
||||||
case Statement.TYPE_SWITCH:
|
|
||||||
case Statement.TYPE_SYNCRONIZED:
|
|
||||||
return findFirstData(stat.getFirst());
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: move to util class (see also InitializerProcessor)
|
|
||||||
private static boolean isInvocationSuperConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper) {
|
|
||||||
|
|
||||||
if (inv.getFunctype() == InvocationExprent.TYP_INIT) {
|
|
||||||
if (inv.getInstance().type == Exprent.EXPRENT_VAR) {
|
|
||||||
VarExprent instvar = (VarExprent)inv.getInstance();
|
|
||||||
VarVersionPaar varpaar = new VarVersionPaar(instvar);
|
|
||||||
|
|
||||||
String classname = meth.varproc.getThisvars().get(varpaar);
|
|
||||||
|
|
||||||
if (classname != null) { // any this instance. TODO: Restrict to current class?
|
|
||||||
if (!wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +1,88 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
|
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
import org.jetbrains.java.decompiler.main.extern.*;
|
||||||
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
|
import org.jetbrains.java.decompiler.modules.renamer.ConverterHelper;
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
|
||||||
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
|
||||||
import org.jetbrains.java.decompiler.modules.renamer.IdentifierConverter;
|
import org.jetbrains.java.decompiler.modules.renamer.IdentifierConverter;
|
||||||
|
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
|
||||||
import org.jetbrains.java.decompiler.struct.IDecompiledData;
|
import org.jetbrains.java.decompiler.struct.IDecompiledData;
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||||
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
||||||
|
import org.jetbrains.java.decompiler.util.TextBuffer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Fernflower implements IDecompiledData {
|
public class Fernflower implements IDecompiledData {
|
||||||
|
private final StructContext structContext;
|
||||||
|
private final ClassesProcessor classProcessor;
|
||||||
|
private final IIdentifierRenamer helper;
|
||||||
|
private final IdentifierConverter converter;
|
||||||
|
|
||||||
private StructContext structContext;
|
public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> customProperties, IFernflowerLogger logger) {
|
||||||
private ClassesProcessor classesProcessor;
|
Map<String, Object> properties = new HashMap<>(IFernflowerPreferences.DEFAULTS);
|
||||||
|
if (customProperties != null) {
|
||||||
|
properties.putAll(customProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
String level = (String)properties.get(IFernflowerPreferences.LOG_LEVEL);
|
||||||
|
if (level != null) {
|
||||||
|
try {
|
||||||
|
logger.setSeverity(IFernflowerLogger.Severity.valueOf(level.toUpperCase(Locale.ENGLISH)));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ignore) { }
|
||||||
|
}
|
||||||
|
|
||||||
public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
|
|
||||||
structContext = new StructContext(saver, this, new LazyLoader(provider));
|
structContext = new StructContext(saver, this, new LazyLoader(provider));
|
||||||
DecompilerContext.initContext(options);
|
classProcessor = new ClassesProcessor(structContext);
|
||||||
DecompilerContext.setCounterContainer(new CounterContainer());
|
|
||||||
DecompilerContext.setLogger(logger);
|
PoolInterceptor interceptor = null;
|
||||||
|
if ("1".equals(properties.get(IFernflowerPreferences.RENAME_ENTITIES))) {
|
||||||
|
helper = loadHelper((String)properties.get(IFernflowerPreferences.USER_RENAMER_CLASS), logger);
|
||||||
|
interceptor = new PoolInterceptor();
|
||||||
|
converter = new IdentifierConverter(structContext, helper, interceptor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
helper = null;
|
||||||
|
converter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecompilerContext context = new DecompilerContext(properties, logger, structContext, classProcessor, interceptor);
|
||||||
|
DecompilerContext.setCurrentContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IIdentifierRenamer loadHelper(String className, IFernflowerLogger logger) {
|
||||||
|
if (className != null) {
|
||||||
|
try {
|
||||||
|
Class<?> renamerClass = Fernflower.class.getClassLoader().loadClass(className);
|
||||||
|
return (IIdentifierRenamer) renamerClass.getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
logger.writeMessage("Cannot load renamer '" + className + "'", IFernflowerLogger.Severity.WARN, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ConverterHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSource(File source) {
|
||||||
|
structContext.addSpace(source, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLibrary(File library) {
|
||||||
|
structContext.addSpace(library, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decompileContext() {
|
public void decompileContext() {
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
|
if (converter != null) {
|
||||||
new IdentifierConverter().rename(structContext);
|
converter.rename();
|
||||||
}
|
}
|
||||||
|
|
||||||
classesProcessor = new ClassesProcessor(structContext);
|
classProcessor.loadClasses(helper);
|
||||||
|
|
||||||
DecompilerContext.setClassProcessor(classesProcessor);
|
|
||||||
DecompilerContext.setStructContext(structContext);
|
|
||||||
|
|
||||||
structContext.saveContext();
|
structContext.saveContext();
|
||||||
}
|
}
|
||||||
@ -58,24 +91,18 @@ public class Fernflower implements IDecompiledData {
|
|||||||
DecompilerContext.setCurrentContext(null);
|
DecompilerContext.setCurrentContext(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StructContext getStructContext() {
|
|
||||||
return structContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClassEntryName(StructClass cl, String entryName) {
|
public String getClassEntryName(StructClass cl, String entryName) {
|
||||||
ClassNode node = classesProcessor.getMapRootClasses().get(cl.qualifiedName);
|
ClassNode node = classProcessor.getMapRootClasses().get(cl.qualifiedName);
|
||||||
if (node.type != ClassNode.CLASS_ROOT) {
|
if (node.type != ClassNode.CLASS_ROOT) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
else if (converter != null) {
|
||||||
|
String simpleClassName = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1);
|
||||||
|
return entryName.substring(0, entryName.lastIndexOf('/') + 1) + simpleClassName + ".java";
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
|
return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java";
|
||||||
String simple_classname = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1);
|
|
||||||
return entryName.substring(0, entryName.lastIndexOf('/') + 1) + simple_classname + ".java";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,12 +111,12 @@ public class Fernflower implements IDecompiledData {
|
|||||||
try {
|
try {
|
||||||
TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);
|
TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);
|
||||||
buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString());
|
buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString());
|
||||||
classesProcessor.writeClass(cl, buffer);
|
classProcessor.writeClass(cl, buffer);
|
||||||
return org.spigotmc.fernflower.EclipseFormatter.format(buffer.toString()); // Spigot
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable t) {
|
||||||
DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex);
|
DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", t);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
package org.jetbrains.java.decompiler.main;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -23,7 +9,8 @@ import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statements;
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructField;
|
import org.jetbrains.java.decompiler.struct.StructField;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
@ -31,14 +18,11 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class InitializerProcessor {
|
||||||
public class InitializerProcessor {
|
|
||||||
|
|
||||||
public static void extractInitializers(ClassWrapper wrapper) {
|
public static void extractInitializers(ClassWrapper wrapper) {
|
||||||
|
MethodWrapper method = wrapper.getMethodWrapper(CodeConstants.CLINIT_NAME, "()V");
|
||||||
MethodWrapper meth = wrapper.getMethodWrapper("<clinit>", "()V");
|
if (method != null && method.root != null) { // successfully decompiled static constructor
|
||||||
if (meth != null && meth.root != null) { // successfully decompiled static constructor
|
extractStaticInitializers(wrapper, method);
|
||||||
extractStaticInitializers(wrapper, meth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDynamicInitializers(wrapper);
|
extractDynamicInitializers(wrapper);
|
||||||
@ -52,30 +36,26 @@ public class InitializerProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void liftConstructor(ClassWrapper wrapper) {
|
private static void liftConstructor(ClassWrapper wrapper) {
|
||||||
|
for (MethodWrapper method : wrapper.getMethods()) {
|
||||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
if (CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && method.root != null) {
|
||||||
if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
|
Statement firstData = Statements.findFirstData(method.root);
|
||||||
Statement firstdata = findFirstData(meth.root);
|
if (firstData == null) {
|
||||||
if (firstdata == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
List<Exprent> lstExprents = firstdata.getExprents();
|
List<Exprent> lstExprents = firstData.getExprents();
|
||||||
|
|
||||||
for (Exprent exprent : lstExprents) {
|
for (Exprent exprent : lstExprents) {
|
||||||
|
|
||||||
int action = 0;
|
int action = 0;
|
||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||||
AssignmentExprent asexpr = (AssignmentExprent)exprent;
|
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
|
||||||
if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
|
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD && assignExpr.getRight().type == Exprent.EXPRENT_VAR) {
|
||||||
FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
|
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
|
||||||
if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
|
if (fExpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
|
||||||
StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString);
|
StructField structField = wrapper.getClassStruct().getField(fExpr.getName(), fExpr.getDescriptor().descriptorString);
|
||||||
if (structField != null && structField.hasModifier(CodeConstants.ACC_FINAL)) {
|
if (structField != null && structField.hasModifier(CodeConstants.ACC_FINAL)) {
|
||||||
action = 1;
|
action = 1;
|
||||||
}
|
}
|
||||||
@ -83,7 +63,7 @@ public class InitializerProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (index > 0 && exprent.type == Exprent.EXPRENT_INVOCATION &&
|
else if (index > 0 && exprent.type == Exprent.EXPRENT_INVOCATION &&
|
||||||
isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, true)) {
|
Statements.isInvocationInitConstructor((InvocationExprent)exprent, method, wrapper, true)) {
|
||||||
// this() or super()
|
// this() or super()
|
||||||
lstExprents.add(0, lstExprents.remove(index));
|
lstExprents.add(0, lstExprents.remove(index));
|
||||||
action = 2;
|
action = 2;
|
||||||
@ -99,52 +79,50 @@ public class InitializerProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void hideEmptySuper(ClassWrapper wrapper) {
|
private static void hideEmptySuper(ClassWrapper wrapper) {
|
||||||
|
for (MethodWrapper method : wrapper.getMethods()) {
|
||||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
if (CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && method.root != null) {
|
||||||
if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
|
Statement firstData = Statements.findFirstData(method.root);
|
||||||
Statement firstdata = findFirstData(meth.root);
|
if (firstData == null || firstData.getExprents().isEmpty()) {
|
||||||
if (firstdata == null || firstdata.getExprents().isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Exprent exprent = firstdata.getExprents().get(0);
|
Exprent exprent = firstData.getExprents().get(0);
|
||||||
if (exprent.type == Exprent.EXPRENT_INVOCATION) {
|
if (exprent.type == Exprent.EXPRENT_INVOCATION) {
|
||||||
InvocationExprent invexpr = (InvocationExprent)exprent;
|
InvocationExprent invExpr = (InvocationExprent)exprent;
|
||||||
if (isInvocationInitConstructor(invexpr, meth, wrapper, false) && invexpr.getLstParameters().isEmpty()) {
|
if (Statements.isInvocationInitConstructor(invExpr, method, wrapper, false) && invExpr.getLstParameters().isEmpty()) {
|
||||||
firstdata.getExprents().remove(0);
|
firstData.getExprents().remove(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper meth) {
|
private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper method) {
|
||||||
|
RootStatement root = method.root;
|
||||||
RootStatement root = meth.root;
|
|
||||||
StructClass cl = wrapper.getClassStruct();
|
StructClass cl = wrapper.getClassStruct();
|
||||||
|
Statement firstData = Statements.findFirstData(root);
|
||||||
|
if (firstData != null) {
|
||||||
|
boolean inlineInitializers = cl.hasModifier(CodeConstants.ACC_INTERFACE) || cl.hasModifier(CodeConstants.ACC_ENUM);
|
||||||
|
|
||||||
Statement firstdata = findFirstData(root);
|
while (!firstData.getExprents().isEmpty()) {
|
||||||
if (firstdata != null) {
|
Exprent exprent = firstData.getExprents().get(0);
|
||||||
while (!firstdata.getExprents().isEmpty()) {
|
|
||||||
Exprent exprent = firstdata.getExprents().get(0);
|
|
||||||
|
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||||
AssignmentExprent asexpr = (AssignmentExprent)exprent;
|
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
|
||||||
if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
||||||
FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
|
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
|
||||||
if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
|
if (fExpr.isStatic() && fExpr.getClassname().equals(cl.qualifiedName) &&
|
||||||
cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) {
|
cl.hasField(fExpr.getName(), fExpr.getDescriptor().descriptorString)) {
|
||||||
|
|
||||||
if (true || isExprentIndependent(asexpr.getRight(), meth)) { // Spigot
|
// interfaces fields should always be initialized inline
|
||||||
|
if (inlineInitializers || isExprentIndependent(assignExpr.getRight(), method)) {
|
||||||
String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
|
String keyField = InterpreterUtil.makeUniqueKey(fExpr.getName(), fExpr.getDescriptor().descriptorString);
|
||||||
if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) {
|
if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) {
|
||||||
wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField);
|
wrapper.getStaticFieldInitializers().addWithKey(assignExpr.getRight(), keyField);
|
||||||
firstdata.getExprents().remove(0);
|
firstData.getExprents().remove(0);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,27 +138,26 @@ public class InitializerProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void extractDynamicInitializers(ClassWrapper wrapper) {
|
private static void extractDynamicInitializers(ClassWrapper wrapper) {
|
||||||
|
|
||||||
StructClass cl = wrapper.getClassStruct();
|
StructClass cl = wrapper.getClassStruct();
|
||||||
|
|
||||||
boolean isAnonymous = DecompilerContext.getClassProcessor().getMapRootClasses().get(cl.qualifiedName).type == ClassNode.CLASS_ANONYMOUS;
|
boolean isAnonymous = DecompilerContext.getClassProcessor().getMapRootClasses().get(cl.qualifiedName).type == ClassNode.CLASS_ANONYMOUS;
|
||||||
|
|
||||||
List<List<Exprent>> lstFirst = new ArrayList<List<Exprent>>();
|
List<List<Exprent>> lstFirst = new ArrayList<>();
|
||||||
List<MethodWrapper> lstMethWrappers = new ArrayList<MethodWrapper>();
|
List<MethodWrapper> lstMethodWrappers = new ArrayList<>();
|
||||||
|
|
||||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
for (MethodWrapper method : wrapper.getMethods()) {
|
||||||
if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) { // successfully decompiled constructor
|
if (CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && method.root != null) { // successfully decompiled constructor
|
||||||
Statement firstdata = findFirstData(meth.root);
|
Statement firstData = Statements.findFirstData(method.root);
|
||||||
if (firstdata == null || firstdata.getExprents().isEmpty()) {
|
if (firstData == null || firstData.getExprents().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lstFirst.add(firstdata.getExprents());
|
lstFirst.add(firstData.getExprents());
|
||||||
lstMethWrappers.add(meth);
|
lstMethodWrappers.add(method);
|
||||||
|
|
||||||
Exprent exprent = firstdata.getExprents().get(0);
|
Exprent exprent = firstData.getExprents().get(0);
|
||||||
if (!isAnonymous) { // FIXME: doesn't make sense
|
if (!isAnonymous) { // FIXME: doesn't make sense
|
||||||
if (exprent.type != Exprent.EXPRENT_INVOCATION ||
|
if (exprent.type != Exprent.EXPRENT_INVOCATION ||
|
||||||
!isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, false)) {
|
!Statements.isInvocationInitConstructor((InvocationExprent)exprent, method, wrapper, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,12 +169,10 @@ public class InitializerProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
String fieldWithDescr = null;
|
String fieldWithDescr = null;
|
||||||
Exprent value = null;
|
Exprent value = null;
|
||||||
|
|
||||||
for (int i = 0; i < lstFirst.size(); i++) {
|
for (int i = 0; i < lstFirst.size(); i++) {
|
||||||
|
|
||||||
List<Exprent> lst = lstFirst.get(i);
|
List<Exprent> lst = lstFirst.get(i);
|
||||||
|
|
||||||
if (lst.size() < (isAnonymous ? 1 : 2)) {
|
if (lst.size() < (isAnonymous ? 1 : 2)) {
|
||||||
@ -209,22 +184,21 @@ public class InitializerProcessor {
|
|||||||
boolean found = false;
|
boolean found = false;
|
||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||||
AssignmentExprent asexpr = (AssignmentExprent)exprent;
|
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
|
||||||
if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
||||||
FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
|
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
|
||||||
if (!fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
|
if (!fExpr.isStatic() && fExpr.getClassname().equals(cl.qualifiedName) &&
|
||||||
cl.hasField(fexpr.getName(), fexpr
|
cl.hasField(fExpr.getName(), fExpr.getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
|
||||||
.getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
|
|
||||||
|
|
||||||
if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i))) {
|
if (isExprentIndependent(assignExpr.getRight(), lstMethodWrappers.get(i))) {
|
||||||
String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
|
String fieldKey = InterpreterUtil.makeUniqueKey(fExpr.getName(), fExpr.getDescriptor().descriptorString);
|
||||||
if (fieldWithDescr == null) {
|
if (fieldWithDescr == null) {
|
||||||
fieldWithDescr = fieldKey;
|
fieldWithDescr = fieldKey;
|
||||||
value = asexpr.getRight();
|
value = assignExpr.getRight();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!fieldWithDescr.equals(fieldKey) ||
|
if (!fieldWithDescr.equals(fieldKey) ||
|
||||||
!value.equals(asexpr.getRight())) {
|
!value.equals(assignExpr.getRight())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,19 +226,17 @@ public class InitializerProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth) {
|
private static boolean isExprentIndependent(Exprent exprent, MethodWrapper method) {
|
||||||
|
|
||||||
List<Exprent> lst = exprent.getAllExprents(true);
|
List<Exprent> lst = exprent.getAllExprents(true);
|
||||||
lst.add(exprent);
|
lst.add(exprent);
|
||||||
|
|
||||||
for (Exprent expr : lst) {
|
for (Exprent expr : lst) {
|
||||||
switch (expr.type) {
|
switch (expr.type) {
|
||||||
case Exprent.EXPRENT_VAR:
|
case Exprent.EXPRENT_VAR:
|
||||||
VarVersionPaar varpaar = new VarVersionPaar((VarExprent)expr);
|
VarVersionPair varPair = new VarVersionPair((VarExprent)expr);
|
||||||
if (!meth.varproc.getExternvars().contains(varpaar)) {
|
if (!method.varproc.getExternalVars().contains(varPair)) {
|
||||||
String varname = meth.varproc.getVarName(varpaar);
|
String varName = method.varproc.getVarName(varPair);
|
||||||
|
if (!varName.equals("this") && !varName.endsWith(".this")) { // FIXME: remove direct comparison with strings
|
||||||
if (!varname.equals("this") && !varname.endsWith(".this")) { // FIXME: remove direct comparison with strings
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,48 +248,4 @@ public class InitializerProcessor {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Statement findFirstData(Statement stat) {
|
|
||||||
|
|
||||||
if (stat.getExprents() != null) {
|
|
||||||
return stat;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (stat.isLabeled()) { // FIXME: Why??
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (stat.type) {
|
|
||||||
case Statement.TYPE_SEQUENCE:
|
|
||||||
case Statement.TYPE_IF:
|
|
||||||
case Statement.TYPE_ROOT:
|
|
||||||
case Statement.TYPE_SWITCH:
|
|
||||||
case Statement.TYPE_SYNCRONIZED:
|
|
||||||
return findFirstData(stat.getFirst());
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isInvocationInitConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper, boolean withThis) {
|
|
||||||
|
|
||||||
if (inv.getFunctype() == InvocationExprent.TYP_INIT) {
|
|
||||||
if (inv.getInstance().type == Exprent.EXPRENT_VAR) {
|
|
||||||
VarExprent instvar = (VarExprent)inv.getInstance();
|
|
||||||
VarVersionPaar varpaar = new VarVersionPaar(instvar);
|
|
||||||
|
|
||||||
String classname = meth.varproc.getThisvars().get(varpaar);
|
|
||||||
|
|
||||||
if (classname != null) { // any this instance. TODO: Restrict to current class?
|
|
||||||
if (withThis || !wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows to connect text with resulting lines
|
|
||||||
*
|
|
||||||
* @author egor
|
|
||||||
*/
|
|
||||||
public class TextBuffer {
|
|
||||||
private final String myLineSeparator = DecompilerContext.getNewLineSeparator();
|
|
||||||
private final String myIndent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
|
|
||||||
private final StringBuilder myStringBuilder;
|
|
||||||
private Map<Integer, Integer> myLineToOffsetMapping = null;
|
|
||||||
|
|
||||||
public TextBuffer() {
|
|
||||||
myStringBuilder = new StringBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer(int size) {
|
|
||||||
myStringBuilder = new StringBuilder(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentLine(int line) {
|
|
||||||
if (line >= 0) {
|
|
||||||
checkMapCreated();
|
|
||||||
myLineToOffsetMapping.put(line, myStringBuilder.length()+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer append(String str) {
|
|
||||||
myStringBuilder.append(str);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer append(char ch) {
|
|
||||||
myStringBuilder.append(ch);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer appendLineSeparator() {
|
|
||||||
myStringBuilder.append(myLineSeparator);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer appendIndent(int length) {
|
|
||||||
while (length-- > 0) {
|
|
||||||
append(myIndent);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer addBanner(String banner) {
|
|
||||||
myStringBuilder.insert(0, banner);
|
|
||||||
if (myLineToOffsetMapping != null) {
|
|
||||||
for (Integer line : myLineToOffsetMapping.keySet()) {
|
|
||||||
myLineToOffsetMapping.put(line, myLineToOffsetMapping.get(line) + banner.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
String original = myStringBuilder.toString();
|
|
||||||
if (myLineToOffsetMapping == null || myLineToOffsetMapping.isEmpty()) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
StringBuilder res = new StringBuilder();
|
|
||||||
String[] srcLines = original.split(myLineSeparator);
|
|
||||||
int currentLineStartOffset = 0;
|
|
||||||
int currentLine = 0;
|
|
||||||
int previousMarkLine = 0;
|
|
||||||
int dumpedLines = 0;
|
|
||||||
ArrayList<Integer> linesWithMarks = new ArrayList<Integer>(myLineToOffsetMapping.keySet());
|
|
||||||
Collections.sort(linesWithMarks);
|
|
||||||
for (Integer markLine : linesWithMarks) {
|
|
||||||
Integer markOffset = myLineToOffsetMapping.get(markLine);
|
|
||||||
while (currentLine < srcLines.length) {
|
|
||||||
String line = srcLines[currentLine];
|
|
||||||
int lineEnd = currentLineStartOffset + line.length() + myLineSeparator.length();
|
|
||||||
if (markOffset >= currentLineStartOffset && markOffset <= lineEnd) {
|
|
||||||
int requiredLinesNumber = markLine - dumpedLines;
|
|
||||||
dumpedLines = markLine;
|
|
||||||
appendLines(res, srcLines, previousMarkLine, currentLine, requiredLinesNumber);
|
|
||||||
previousMarkLine = currentLine;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
currentLineStartOffset = lineEnd;
|
|
||||||
currentLine++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (previousMarkLine < srcLines.length) {
|
|
||||||
appendLines(res, srcLines, previousMarkLine, srcLines.length, srcLines.length - previousMarkLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendLines(StringBuilder res, String[] srcLines, int from, int to, int requiredLineNumber) {
|
|
||||||
if (to - from > requiredLineNumber) {
|
|
||||||
int separatorsRequired = to - from - requiredLineNumber - 1;
|
|
||||||
for (int i = from; i < to; i++) {
|
|
||||||
res.append(srcLines[i]);
|
|
||||||
if (separatorsRequired-- > 0) {
|
|
||||||
res.append(myLineSeparator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.append(myLineSeparator);
|
|
||||||
}
|
|
||||||
else if (to - from <= requiredLineNumber) {
|
|
||||||
for (int i = from; i < to; i++) {
|
|
||||||
res.append(srcLines[i]).append(myLineSeparator);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < requiredLineNumber - to + from; i++) {
|
|
||||||
res.append(myLineSeparator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return myStringBuilder.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String substring(int start) {
|
|
||||||
return myStringBuilder.substring(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLength(int position) {
|
|
||||||
myStringBuilder.setLength(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer append(TextBuffer buffer) {
|
|
||||||
if (buffer.myLineToOffsetMapping != null && !buffer.myLineToOffsetMapping.isEmpty()) {
|
|
||||||
checkMapCreated();
|
|
||||||
for (Map.Entry<Integer, Integer> entry : buffer.myLineToOffsetMapping.entrySet()) {
|
|
||||||
myLineToOffsetMapping.put(entry.getKey(), entry.getValue() + myStringBuilder.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myStringBuilder.append(buffer.myStringBuilder);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkMapCreated() {
|
|
||||||
if (myLineToOffsetMapping == null) {
|
|
||||||
myLineToOffsetMapping = new HashMap<Integer, Integer>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insert(int offset, String s) {
|
|
||||||
if (myLineToOffsetMapping != null) {
|
|
||||||
throw new IllegalStateException("insert not yet supported with Line mapping");
|
|
||||||
}
|
|
||||||
myStringBuilder.insert(offset, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int count(String substring, int from) {
|
|
||||||
int count = 0, length = substring.length(), p = from;
|
|
||||||
while ((p = myStringBuilder.indexOf(substring, p)) > 0) {
|
|
||||||
++count;
|
|
||||||
p += length;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +1,103 @@
|
|||||||
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
package org.jetbrains.java.decompiler.main.collectors;
|
package org.jetbrains.java.decompiler.main.collectors;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import org.jetbrains.java.decompiler.struct.attr.StructLineNumberTableAttribute;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class BytecodeMappingTracer {
|
public class BytecodeMappingTracer {
|
||||||
|
public static final BytecodeMappingTracer DUMMY = new BytecodeMappingTracer();
|
||||||
|
|
||||||
private int current_sourceline;
|
private int currentSourceLine;
|
||||||
|
private StructLineNumberTableAttribute lineNumberTable = null;
|
||||||
|
private final Map<Integer, Integer> mapping = new HashMap<>(); // bytecode offset, source line
|
||||||
|
|
||||||
// bytecode offset, source line
|
public BytecodeMappingTracer() { }
|
||||||
private HashMap<Integer, Integer> mapping = new HashMap<Integer, Integer>();
|
|
||||||
|
|
||||||
public BytecodeMappingTracer() {}
|
|
||||||
|
|
||||||
public BytecodeMappingTracer(int initial_source_line) {
|
public BytecodeMappingTracer(int initial_source_line) {
|
||||||
current_sourceline = initial_source_line;
|
currentSourceLine = initial_source_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incrementCurrentSourceLine() {
|
public void incrementCurrentSourceLine() {
|
||||||
current_sourceline++;
|
currentSourceLine++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incrementCurrentSourceLine(int number_lines) {
|
public void incrementCurrentSourceLine(int number_lines) {
|
||||||
current_sourceline += number_lines;
|
currentSourceLine += number_lines;
|
||||||
}
|
|
||||||
|
|
||||||
public void shiftSourceLines(int shift) {
|
|
||||||
for(Entry<Integer, Integer> entry : mapping.entrySet()) {
|
|
||||||
entry.setValue(entry.getValue() + shift);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMapping(int bytecode_offset) {
|
public void addMapping(int bytecode_offset) {
|
||||||
if(!mapping.containsKey(bytecode_offset)) {
|
mapping.putIfAbsent(bytecode_offset, currentSourceLine);
|
||||||
mapping.put(bytecode_offset, current_sourceline);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMapping(Set<Integer> bytecode_offsets) {
|
public void addMapping(Set<Integer> bytecode_offsets) {
|
||||||
if(bytecode_offsets != null) {
|
if (bytecode_offsets != null) {
|
||||||
for(Integer bytecode_offset : bytecode_offsets) {
|
for (Integer bytecode_offset : bytecode_offsets) {
|
||||||
addMapping(bytecode_offset);
|
addMapping(bytecode_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTracer(BytecodeMappingTracer tracer) {
|
public void addTracer(BytecodeMappingTracer tracer) {
|
||||||
if(tracer != null) {
|
if (tracer != null) {
|
||||||
for(Entry<Integer, Integer> entry : tracer.mapping.entrySet()) {
|
for (Entry<Integer, Integer> entry : tracer.mapping.entrySet()) {
|
||||||
if(!mapping.containsKey(entry.getKey())) {
|
mapping.putIfAbsent(entry.getKey(), entry.getValue());
|
||||||
mapping.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<Integer, Integer> getMapping() {
|
public Map<Integer, Integer> getMapping() {
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentSourceLine() {
|
public int getCurrentSourceLine() {
|
||||||
return current_sourceline;
|
return currentSourceLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentSourceLine(int current_sourceline) {
|
public void setCurrentSourceLine(int currentSourceLine) {
|
||||||
this.current_sourceline = current_sourceline;
|
this.currentSourceLine = currentSourceLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public void setLineNumberTable(StructLineNumberTableAttribute lineNumberTable) {
|
||||||
|
this.lineNumberTable = lineNumberTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Set<Integer> unmappedLines = new HashSet<>();
|
||||||
|
|
||||||
|
public Set<Integer> getUnmappedLines() {
|
||||||
|
return unmappedLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Integer> getOriginalLinesMapping() {
|
||||||
|
if (lineNumberTable == null) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, Integer> res = new HashMap<>();
|
||||||
|
|
||||||
|
// first match offsets from line number table
|
||||||
|
int[] data = lineNumberTable.getRawData();
|
||||||
|
for (int i = 0; i < data.length; i += 2) {
|
||||||
|
int originalOffset = data[i];
|
||||||
|
int originalLine = data[i + 1];
|
||||||
|
Integer newLine = mapping.get(originalOffset);
|
||||||
|
if (newLine != null) {
|
||||||
|
res.put(originalLine, newLine);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unmappedLines.add(originalLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now match offsets from decompiler mapping
|
||||||
|
for (Entry<Integer, Integer> entry : mapping.entrySet()) {
|
||||||
|
int originalLine = lineNumberTable.findLineNumber(entry.getKey());
|
||||||
|
if (originalLine > -1 && !res.containsKey(originalLine)) {
|
||||||
|
res.put(originalLine, entry.getValue());
|
||||||
|
unmappedLines.remove(originalLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -1,81 +1,109 @@
|
|||||||
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
package org.jetbrains.java.decompiler.main.collectors;
|
package org.jetbrains.java.decompiler.main.collectors;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
import org.jetbrains.java.decompiler.main.TextBuffer;
|
import org.jetbrains.java.decompiler.util.TextBuffer;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public class BytecodeSourceMapper {
|
public class BytecodeSourceMapper {
|
||||||
|
|
||||||
private int offset_total;
|
private int offset_total;
|
||||||
|
|
||||||
// class, method, bytecode offset, source line
|
// class, method, bytecode offset, source line
|
||||||
private HashMap<String, HashMap<String, HashMap<Integer, Integer>>> mapping = new HashMap<String, HashMap<String, HashMap<Integer, Integer>>>();
|
private final Map<String, Map<String, Map<Integer, Integer>>> mapping = new LinkedHashMap<>();
|
||||||
|
|
||||||
public void addMapping(String classname, String methodname, int bytecode_offset, int source_line) {
|
// original line to decompiled line
|
||||||
|
private final Map<Integer, Integer> linesMapping = new HashMap<>();
|
||||||
|
private final Set<Integer> unmappedLines = new TreeSet<>();
|
||||||
|
|
||||||
HashMap<String, HashMap<Integer, Integer>> class_mapping = mapping.get(classname);
|
public void addMapping(String className, String methodName, int bytecodeOffset, int sourceLine) {
|
||||||
if(class_mapping == null) {
|
Map<String, Map<Integer, Integer>> class_mapping = mapping.computeIfAbsent(className, k -> new LinkedHashMap<>()); // need to preserve order
|
||||||
mapping.put(classname, class_mapping = new HashMap<String, HashMap<Integer, Integer>>());
|
Map<Integer, Integer> method_mapping = class_mapping.computeIfAbsent(methodName, k -> new HashMap<>());
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<Integer, Integer> method_mapping = class_mapping.get(methodname);
|
|
||||||
if(method_mapping == null) {
|
|
||||||
class_mapping.put(methodname, method_mapping = new HashMap<Integer, Integer>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't overwrite
|
// don't overwrite
|
||||||
if(!method_mapping.containsKey(bytecode_offset)) {
|
method_mapping.putIfAbsent(bytecodeOffset, sourceLine);
|
||||||
method_mapping.put(bytecode_offset, source_line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTracer(String classname, String methodname, BytecodeMappingTracer tracer) {
|
public void addTracer(String className, String methodName, BytecodeMappingTracer tracer) {
|
||||||
for(Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
|
for (Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
|
||||||
addMapping(classname, methodname, entry.getKey(), entry.getValue());
|
addMapping(className, methodName, entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
linesMapping.putAll(tracer.getOriginalLinesMapping());
|
||||||
|
unmappedLines.addAll(tracer.getUnmappedLines());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpMapping(TextBuffer buffer) {
|
public void dumpMapping(TextBuffer buffer, boolean offsetsToHex) {
|
||||||
|
if (mapping.isEmpty() && linesMapping.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String lineSeparator = DecompilerContext.getNewLineSeparator();
|
String lineSeparator = DecompilerContext.getNewLineSeparator();
|
||||||
|
|
||||||
for(Entry<String, HashMap<String, HashMap<Integer, Integer>>> class_entry : mapping.entrySet()) {
|
for (Entry<String, Map<String, Map<Integer, Integer>>> class_entry : mapping.entrySet()) {
|
||||||
HashMap<String, HashMap<Integer, Integer>> class_mapping = class_entry.getValue();
|
Map<String, Map<Integer, Integer>> class_mapping = class_entry.getValue();
|
||||||
buffer.append("class " + class_entry.getKey() + "{" + lineSeparator);
|
buffer.append("class '" + class_entry.getKey() + "' {" + lineSeparator);
|
||||||
|
|
||||||
boolean is_first_method = true;
|
boolean is_first_method = true;
|
||||||
|
for (Entry<String, Map<Integer, Integer>> method_entry : class_mapping.entrySet()) {
|
||||||
|
Map<Integer, Integer> method_mapping = method_entry.getValue();
|
||||||
|
|
||||||
for(Entry<String, HashMap<Integer, Integer>> method_entry : class_mapping.entrySet()) {
|
if (!is_first_method) {
|
||||||
HashMap<Integer, Integer> method_mapping = method_entry.getValue();
|
|
||||||
|
|
||||||
if(!is_first_method) {
|
|
||||||
buffer.appendLineSeparator();
|
buffer.appendLineSeparator();
|
||||||
}
|
}
|
||||||
buffer.appendIndent(1).append("method " + method_entry.getKey() + "{" + lineSeparator);
|
|
||||||
|
|
||||||
for(Entry<Integer, Integer> line : method_mapping.entrySet()) {
|
buffer.appendIndent(1).append("method '" + method_entry.getKey() + "' {" + lineSeparator);
|
||||||
buffer.appendIndent(2).append(line.getKey().toString()).appendIndent(2).append((line.getValue() + offset_total) + lineSeparator);
|
|
||||||
|
List<Integer> lstBytecodeOffsets = new ArrayList<>(method_mapping.keySet());
|
||||||
|
Collections.sort(lstBytecodeOffsets);
|
||||||
|
|
||||||
|
for (Integer offset : lstBytecodeOffsets) {
|
||||||
|
Integer line = method_mapping.get(offset);
|
||||||
|
|
||||||
|
String strOffset = offsetsToHex ? Integer.toHexString(offset) : line.toString();
|
||||||
|
buffer.appendIndent(2).append(strOffset).appendIndent(2).append((line + offset_total) + lineSeparator);
|
||||||
}
|
}
|
||||||
buffer.appendIndent(1).append("}").appendLineSeparator();
|
buffer.appendIndent(1).append("}").appendLineSeparator();
|
||||||
|
|
||||||
is_first_method = false;
|
is_first_method = false;
|
||||||
}
|
}
|
||||||
buffer.append("}").appendLineSeparator();
|
|
||||||
|
buffer.append("}").appendLineSeparator().appendLineSeparator();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int getTotalOffset() {
|
// lines mapping
|
||||||
return offset_total;
|
buffer.append("Lines mapping:").appendLineSeparator();
|
||||||
}
|
Map<Integer, Integer> sorted = new TreeMap<>(linesMapping);
|
||||||
|
for (Entry<Integer, Integer> entry : sorted.entrySet()) {
|
||||||
|
buffer.append(entry.getKey()).append(" <-> ").append(entry.getValue() + offset_total + 1).appendLineSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
public void setTotalOffset(int offset_total) {
|
if (!unmappedLines.isEmpty()) {
|
||||||
this.offset_total = offset_total;
|
buffer.append("Not mapped:").appendLineSeparator();
|
||||||
|
for (Integer line : unmappedLines) {
|
||||||
|
if (!linesMapping.containsKey(line)) {
|
||||||
|
buffer.append(line).appendLineSeparator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTotalOffset(int offset_total) {
|
public void addTotalOffset(int offset_total) {
|
||||||
this.offset_total += offset_total;
|
this.offset_total += offset_total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
}
|
* Original to decompiled line mapping.
|
||||||
|
*/
|
||||||
|
public int[] getOriginalLinesMapping() {
|
||||||
|
int[] res = new int[linesMapping.size() * 2];
|
||||||
|
int i = 0;
|
||||||
|
for (Entry<Integer, Integer> entry : linesMapping.entrySet()) {
|
||||||
|
res[i] = entry.getKey();
|
||||||
|
unmappedLines.remove(entry.getKey());
|
||||||
|
res[i + 1] = entry.getValue() + offset_total + 1; // make it 1 based
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,12 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.collectors;
|
package org.jetbrains.java.decompiler.main.collectors;
|
||||||
|
|
||||||
public class CounterContainer {
|
public class CounterContainer {
|
||||||
|
|
||||||
public static final int STATEMENT_COUNTER = 0;
|
public static final int STATEMENT_COUNTER = 0;
|
||||||
public static final int EXPRENT_COUNTER = 1;
|
public static final int EXPRESSION_COUNTER = 1;
|
||||||
public static final int VAR_COUNTER = 2;
|
public static final int VAR_COUNTER = 2;
|
||||||
|
|
||||||
private int[] values = new int[]{1, 1, 1};
|
private final int[] values = new int[]{1, 1, 1};
|
||||||
|
|
||||||
public void setCounter(int counter, int value) {
|
public void setCounter(int counter, int value) {
|
||||||
values[counter] = value;
|
values[counter] = value;
|
||||||
@ -34,4 +19,4 @@ public class CounterContainer {
|
|||||||
public int getCounterAndIncrement(int counter) {
|
public int getCounterAndIncrement(int counter) {
|
||||||
return values[counter]++;
|
return values[counter]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,155 +1,186 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.collectors;
|
package org.jetbrains.java.decompiler.main.collectors;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.ClassesProcessor;
|
|
||||||
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
|
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
import org.jetbrains.java.decompiler.main.TextBuffer;
|
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||||
|
import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute;
|
||||||
|
import org.jetbrains.java.decompiler.util.TextBuffer;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructField;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
public class ImportCollector {
|
public class ImportCollector {
|
||||||
|
|
||||||
private static final String JAVA_LANG_PACKAGE = "java.lang";
|
private static final String JAVA_LANG_PACKAGE = "java.lang";
|
||||||
|
|
||||||
private Map<String, String> mapSimpleNames = new HashMap<String, String>();
|
private final Map<String, String> mapSimpleNames = new HashMap<>();
|
||||||
private Set<String> setNotImportedNames = new HashSet<String>();
|
private final Set<String> setNotImportedNames = new HashSet<>();
|
||||||
private String currentPackageSlash = "";
|
// set of field names in this class and all its predecessors.
|
||||||
private String currentPackagePoint = "";
|
private final Set<String> setFieldNames = new HashSet<>();
|
||||||
|
private final Set<String> setInnerClassNames = new HashSet<>();
|
||||||
|
private final String currentPackageSlash;
|
||||||
|
private final String currentPackagePoint;
|
||||||
|
|
||||||
public ImportCollector(ClassNode root) {
|
public ImportCollector(ClassNode root) {
|
||||||
|
String clName = root.classStruct.qualifiedName;
|
||||||
String clname = root.classStruct.qualifiedName;
|
int index = clName.lastIndexOf('/');
|
||||||
int index = clname.lastIndexOf("/");
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
currentPackageSlash = clname.substring(0, index);
|
String packageName = clName.substring(0, index);
|
||||||
currentPackagePoint = currentPackageSlash.replace('/', '.');
|
currentPackageSlash = packageName + '/';
|
||||||
currentPackageSlash += "/";
|
currentPackagePoint = packageName.replace('/', '.');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentPackageSlash = "";
|
||||||
|
currentPackagePoint = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, StructClass> classes = DecompilerContext.getStructContext().getClasses();
|
||||||
|
LinkedList<String> queue = new LinkedList<>();
|
||||||
|
Set<StructClass> processedClasses = new HashSet<>();
|
||||||
|
StructClass currentClass = root.classStruct;
|
||||||
|
while (currentClass != null) {
|
||||||
|
processedClasses.add(currentClass);
|
||||||
|
if (currentClass.superClass != null) {
|
||||||
|
queue.add(currentClass.superClass.getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.addAll(queue, currentClass.getInterfaceNames());
|
||||||
|
|
||||||
|
// all field names for the current class ..
|
||||||
|
for (StructField f : currentClass.getFields()) {
|
||||||
|
setFieldNames.add(f.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// .. all inner classes for the current class ..
|
||||||
|
StructInnerClassesAttribute attribute = currentClass.getAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES);
|
||||||
|
if (attribute != null) {
|
||||||
|
for (StructInnerClassesAttribute.Entry entry : attribute.getEntries()) {
|
||||||
|
if (entry.enclosingName != null && entry.enclosingName.equals(currentClass.qualifiedName)) {
|
||||||
|
setInnerClassNames.add(entry.simpleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// .. and traverse through parent.
|
||||||
|
do {
|
||||||
|
currentClass = queue.isEmpty() ? null : classes.get(queue.removeFirst());
|
||||||
|
|
||||||
|
if (currentClass != null && processedClasses.contains(currentClass)) {
|
||||||
|
// Class already processed, skipping.
|
||||||
|
|
||||||
|
// This may be sign of circularity in the class hierarchy but in most cases this mean that same interface
|
||||||
|
// are listed as implemented several times in the class hierarchy.
|
||||||
|
currentClass = null;
|
||||||
|
}
|
||||||
|
} while (currentClass == null && !queue.isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getShortName(String fullname) {
|
/**
|
||||||
return getShortName(fullname, true);
|
* Check whether the package-less name ClassName is shaded by variable in a context of
|
||||||
|
* the decompiled class
|
||||||
|
* @param classToName - pkg.name.ClassName - class to find shortname for
|
||||||
|
* @return ClassName if the name is not shaded by local field, pkg.name.ClassName otherwise
|
||||||
|
*/
|
||||||
|
public String getShortNameInClassContext(String classToName) {
|
||||||
|
String shortName = getShortName(classToName);
|
||||||
|
if (setFieldNames.contains(shortName)) {
|
||||||
|
return classToName;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getShortName(String fullname, boolean imported) {
|
public String getShortName(String fullName) {
|
||||||
|
return getShortName(fullName, true);
|
||||||
|
}
|
||||||
|
|
||||||
ClassesProcessor clproc = DecompilerContext.getClassProcessor();
|
public String getShortName(String fullName, boolean imported) {
|
||||||
ClassNode node = clproc.getMapRootClasses().get(fullname.replace('.', '/'));
|
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(fullName.replace('.', '/')); //todo[r.sh] anonymous classes?
|
||||||
|
|
||||||
String retname = null;
|
|
||||||
|
|
||||||
|
String result = null;
|
||||||
if (node != null && node.classStruct.isOwn()) {
|
if (node != null && node.classStruct.isOwn()) {
|
||||||
|
result = node.simpleName;
|
||||||
retname = node.simpleName;
|
|
||||||
|
|
||||||
while (node.parent != null && node.type == ClassNode.CLASS_MEMBER) {
|
while (node.parent != null && node.type == ClassNode.CLASS_MEMBER) {
|
||||||
retname = node.parent.simpleName + "." + retname;
|
//noinspection StringConcatenationInLoop
|
||||||
|
result = node.parent.simpleName + '.' + result;
|
||||||
node = node.parent;
|
node = node.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.type == ClassNode.CLASS_ROOT) {
|
if (node.type == ClassNode.CLASS_ROOT) {
|
||||||
fullname = node.classStruct.qualifiedName;
|
fullName = node.classStruct.qualifiedName;
|
||||||
fullname = fullname.replace('/', '.');
|
fullName = fullName.replace('/', '.');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return retname;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fullname = fullname.replace('$', '.');
|
fullName = fullName.replace('$', '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
String nshort = fullname;
|
String shortName = fullName;
|
||||||
String npackage = "";
|
String packageName = "";
|
||||||
|
|
||||||
int lastpoint = fullname.lastIndexOf(".");
|
int lastDot = fullName.lastIndexOf('.');
|
||||||
|
if (lastDot >= 0) {
|
||||||
if (lastpoint >= 0) {
|
shortName = fullName.substring(lastDot + 1);
|
||||||
nshort = fullname.substring(lastpoint + 1);
|
packageName = fullName.substring(0, lastDot);
|
||||||
npackage = fullname.substring(0, lastpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StructContext context = DecompilerContext.getStructContext();
|
StructContext context = DecompilerContext.getStructContext();
|
||||||
|
|
||||||
boolean existsDefaultClass = (context.getClass(currentPackageSlash + nshort) != null
|
// check for another class which could 'shadow' this one. Three cases:
|
||||||
&& !npackage.equals(currentPackagePoint)) // current package
|
// 1) class with the same short name in the current package
|
||||||
|| (context.getClass(nshort) != null); // default package
|
// 2) class with the same short name in the default package
|
||||||
|
// 3) inner class with the same short name in the current class, a super class, or an implemented interface
|
||||||
|
boolean existsDefaultClass =
|
||||||
|
(context.getClass(currentPackageSlash + shortName) != null && !packageName.equals(currentPackagePoint)) || // current package
|
||||||
|
(context.getClass(shortName) != null && !currentPackagePoint.isEmpty()) || // default package
|
||||||
|
setInnerClassNames.contains(shortName); // inner class
|
||||||
|
|
||||||
if (existsDefaultClass ||
|
if (existsDefaultClass ||
|
||||||
(mapSimpleNames.containsKey(nshort) && !npackage.equals(mapSimpleNames.get(nshort)))) {
|
(mapSimpleNames.containsKey(shortName) && !packageName.equals(mapSimpleNames.get(shortName)))) {
|
||||||
return fullname;
|
// don't return full name because if the class is a inner class, full name refers to the parent full name, not the child full name
|
||||||
|
return result == null ? fullName : (packageName + "." + result);
|
||||||
}
|
}
|
||||||
else if (!mapSimpleNames.containsKey(nshort)) {
|
else if (!mapSimpleNames.containsKey(shortName)) {
|
||||||
mapSimpleNames.put(nshort, npackage);
|
mapSimpleNames.put(shortName, packageName);
|
||||||
|
|
||||||
if (!imported) {
|
if (!imported) {
|
||||||
setNotImportedNames.add(nshort);
|
setNotImportedNames.add(shortName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retname == null ? nshort : retname;
|
return result == null ? shortName : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int writeImports(TextBuffer buffer) {
|
public void writeImports(TextBuffer buffer, boolean addSeparator) {
|
||||||
|
|
||||||
int importlines_written = 0;
|
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
|
||||||
|
|
||||||
List<String> imports = packImports();
|
List<String> imports = packImports();
|
||||||
|
for (String line : imports) {
|
||||||
for (String s : imports) {
|
buffer.append("import ").append(line).append(';').appendLineSeparator();
|
||||||
buffer.append("import ");
|
}
|
||||||
buffer.append(s);
|
if (addSeparator && !imports.isEmpty()) {
|
||||||
buffer.append(";");
|
buffer.appendLineSeparator();
|
||||||
buffer.append(new_line_separator);
|
|
||||||
|
|
||||||
importlines_written++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return importlines_written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> packImports() {
|
private List<String> packImports() {
|
||||||
List<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(mapSimpleNames.entrySet());
|
return mapSimpleNames.entrySet().stream()
|
||||||
|
.filter(ent ->
|
||||||
Collections.sort(lst, new Comparator<Entry<String, String>>() {
|
// exclude the current class or one of the nested ones
|
||||||
public int compare(Entry<String, String> par0, Entry<String, String> par1) {
|
// empty, java.lang and the current packages
|
||||||
int res = par0.getValue().compareTo(par1.getValue());
|
!setNotImportedNames.contains(ent.getKey()) &&
|
||||||
if (res == 0) {
|
!ent.getValue().isEmpty() &&
|
||||||
res = par0.getKey().compareTo(par1.getKey());
|
!JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
|
||||||
}
|
!ent.getValue().equals(currentPackagePoint)
|
||||||
return res;
|
)
|
||||||
}
|
.sorted(Map.Entry.<String, String>comparingByValue().thenComparing(Map.Entry.comparingByKey()))
|
||||||
});
|
.map(ent -> ent.getValue() + "." + ent.getKey())
|
||||||
|
.collect(Collectors.toList());
|
||||||
List<String> res = new ArrayList<String>();
|
|
||||||
for (Entry<String, String> ent : lst) {
|
|
||||||
// exclude a current class or one of the nested ones, java.lang and empty packages
|
|
||||||
if (!setNotImportedNames.contains(ent.getKey()) &&
|
|
||||||
!JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
|
|
||||||
!ent.getValue().isEmpty() && !ent.getValue().equals(this.currentPackagePoint)) { // Spigot: Remove same package imports
|
|
||||||
res.add(ent.getValue() + "." + ent.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,20 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.collectors;
|
package org.jetbrains.java.decompiler.main.collectors;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class VarNamesCollector {
|
public class VarNamesCollector {
|
||||||
|
|
||||||
private HashSet<String> usedNames = new HashSet<String>();
|
private final Set<String> usedNames = new HashSet<>();
|
||||||
|
|
||||||
public VarNamesCollector() {
|
public VarNamesCollector() { }
|
||||||
}
|
|
||||||
|
|
||||||
public VarNamesCollector(Collection<String> setNames) {
|
public VarNamesCollector(Collection<String> setNames) {
|
||||||
usedNames.addAll(setNames);
|
usedNames.addAll(setNames);
|
||||||
@ -33,20 +24,140 @@ public class VarNamesCollector {
|
|||||||
usedNames.add(value);
|
usedNames.add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFreeName(int index) {
|
|
||||||
return getFreeName("var" + index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFreeName(String proposition) {
|
public static String removePrefix(String str, String prefix)
|
||||||
|
{
|
||||||
while (usedNames.contains(proposition)) {
|
if (str.toLowerCase().startsWith(prefix))
|
||||||
proposition += "x";
|
{
|
||||||
|
return str.substring(prefix.length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
usedNames.add(proposition);
|
|
||||||
return proposition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashSet<String> getUsedNames() {
|
public String getTypeLabel(VarType type, int index) {
|
||||||
return usedNames;
|
return getTypeLabel(type, index, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getTypeLabel(VarType type, int index, boolean rand) {
|
||||||
|
String typeName = "tl_var" + index;
|
||||||
|
|
||||||
|
// nasty hack
|
||||||
|
|
||||||
|
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (type.type == CodeConstants.TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
typeName = ExprProcessor.getTypeName(type, true);
|
||||||
|
typeName = removePrefix(typeName,"abstract");
|
||||||
|
typeName = removePrefix(typeName,"client");
|
||||||
|
|
||||||
|
typeName = Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1);
|
||||||
|
|
||||||
|
switch (typeName)
|
||||||
|
{
|
||||||
|
case "class":
|
||||||
|
{
|
||||||
|
typeName = "clazz";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "integer":
|
||||||
|
{
|
||||||
|
typeName = "i";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "long":
|
||||||
|
{
|
||||||
|
typeName = "l";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "int":
|
||||||
|
{
|
||||||
|
typeName = "i";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "boolean":
|
||||||
|
{
|
||||||
|
typeName = "bool";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "float":
|
||||||
|
{
|
||||||
|
typeName = "f";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "double":
|
||||||
|
{
|
||||||
|
typeName = "d";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "short":
|
||||||
|
{
|
||||||
|
typeName = "s";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "byte":
|
||||||
|
{
|
||||||
|
typeName = "b";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "enum":
|
||||||
|
{
|
||||||
|
typeName = "e";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type.type == CodeConstants.TYPE_NULL)
|
||||||
|
{
|
||||||
|
typeName = "null";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
typeName = String.valueOf(VarType.getTypeReverse(type)).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName.contains("."))
|
||||||
|
{
|
||||||
|
typeName = typeName.substring(0, typeName.indexOf('.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName.equals("void"))
|
||||||
|
typeName = "v";
|
||||||
|
|
||||||
|
if (typeName.equals("enum"))
|
||||||
|
typeName = "e";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!rand)
|
||||||
|
{
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usedNames.contains(typeName))
|
||||||
|
{
|
||||||
|
return getFreeName(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
addName(typeName);
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
public String getFreeName(String proposition) {
|
||||||
|
int i = 2;
|
||||||
|
String actual = proposition;
|
||||||
|
while (usedNames.contains(actual)) {
|
||||||
|
actual = proposition + i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
usedNames.add(actual);
|
||||||
|
return actual;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.decompiler;
|
package org.jetbrains.java.decompiler.main.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.Fernflower;
|
import org.jetbrains.java.decompiler.main.Fernflower;
|
||||||
@ -21,27 +7,30 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
|||||||
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class BaseDecompiler {
|
public class BaseDecompiler {
|
||||||
|
private final Fernflower engine;
|
||||||
private final Fernflower fernflower;
|
|
||||||
|
|
||||||
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
|
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
|
||||||
fernflower = new Fernflower(provider, saver, options, logger);
|
engine = new Fernflower(provider, saver, options, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSpace(File file, boolean isOwn) throws IOException {
|
public void addSource(File source) {
|
||||||
fernflower.getStructContext().addSpace(file, isOwn);
|
engine.addSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLibrary(File library) {
|
||||||
|
engine.addLibrary(library);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decompileContext() {
|
public void decompileContext() {
|
||||||
try {
|
try {
|
||||||
fernflower.decompileContext();
|
engine.decompileContext();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
fernflower.clearContext();
|
engine.clearContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.decompiler;
|
package org.jetbrains.java.decompiler.main.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
@ -23,6 +9,7 @@ import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
|||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.JarOutputStream;
|
import java.util.jar.JarOutputStream;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
@ -31,7 +18,6 @@ import java.util.zip.ZipFile;
|
|||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||||
|
|
||||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
@ -41,21 +27,20 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> mapOptions = new HashMap<String, Object>();
|
Map<String, Object> mapOptions = new HashMap<>();
|
||||||
List<String> lstSources = new ArrayList<String>();
|
List<File> sources = new ArrayList<>();
|
||||||
List<String> lstLibraries = new ArrayList<String>();
|
List<File> libraries = new ArrayList<>();
|
||||||
|
|
||||||
boolean isOption = true;
|
boolean isOption = true;
|
||||||
for (int i = 0; i < args.length - 1; ++i) { // last parameter - destination
|
for (int i = 0; i < args.length - 1; ++i) { // last parameter - destination
|
||||||
String arg = args[i];
|
String arg = args[i];
|
||||||
|
|
||||||
if (isOption && arg.startsWith("-") &&
|
if (isOption && arg.length() > 5 && arg.charAt(0) == '-' && arg.charAt(4) == '=') {
|
||||||
arg.length() > 5 && arg.charAt(4) == '=') {
|
String value = arg.substring(5);
|
||||||
String value = arg.substring(5).toUpperCase(Locale.US);
|
if ("true".equalsIgnoreCase(value)) {
|
||||||
if ("TRUE".equals(value)) {
|
|
||||||
value = "1";
|
value = "1";
|
||||||
}
|
}
|
||||||
else if ("FALSE".equals(value)) {
|
else if ("false".equalsIgnoreCase(value)) {
|
||||||
value = "0";
|
value = "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,15 +50,15 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
isOption = false;
|
isOption = false;
|
||||||
|
|
||||||
if (arg.startsWith("-e=")) {
|
if (arg.startsWith("-e=")) {
|
||||||
lstLibraries.add(arg.substring(3));
|
addPath(libraries, arg.substring(3));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lstSources.add(arg);
|
addPath(sources, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lstSources.isEmpty()) {
|
if (sources.isEmpty()) {
|
||||||
System.out.println("error: no sources given");
|
System.out.println("error: no sources given");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,45 +72,55 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
PrintStreamLogger logger = new PrintStreamLogger(System.out);
|
PrintStreamLogger logger = new PrintStreamLogger(System.out);
|
||||||
ConsoleDecompiler decompiler = new ConsoleDecompiler(destination, mapOptions, logger);
|
ConsoleDecompiler decompiler = new ConsoleDecompiler(destination, mapOptions, logger);
|
||||||
|
|
||||||
for (String source : lstSources) {
|
for (File library : libraries) {
|
||||||
decompiler.addSpace(new File(source), true);
|
decompiler.addLibrary(library);
|
||||||
}
|
}
|
||||||
for (String library : lstLibraries) {
|
for (File source : sources) {
|
||||||
decompiler.addSpace(new File(library), false);
|
decompiler.addSource(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
decompiler.decompileContext();
|
decompiler.decompileContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||||
|
private static void addPath(List<? super File> list, String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
if (file.exists()) {
|
||||||
|
list.add(file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.out.println("warn: missing '" + path + "', ignored");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// *******************************************************************
|
// *******************************************************************
|
||||||
// Implementation
|
// Implementation
|
||||||
// *******************************************************************
|
// *******************************************************************
|
||||||
|
|
||||||
private final File root;
|
private final File root;
|
||||||
private final Fernflower fernflower;
|
private final Fernflower engine;
|
||||||
private Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<String, ZipOutputStream>();
|
private final Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<>();
|
||||||
private Map<String, Set<String>> mapArchiveEntries = new HashMap<String, Set<String>>();
|
private final Map<String, Set<String>> mapArchiveEntries = new HashMap<>();
|
||||||
|
|
||||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
|
||||||
public ConsoleDecompiler(File destination, Map<String, Object> options) {
|
|
||||||
this(destination, options, new PrintStreamLogger(System.out));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ConsoleDecompiler(File destination, Map<String, Object> options, IFernflowerLogger logger) {
|
protected ConsoleDecompiler(File destination, Map<String, Object> options, IFernflowerLogger logger) {
|
||||||
root = destination;
|
root = destination;
|
||||||
fernflower = new Fernflower(this, this, options, logger);
|
engine = new Fernflower(this, this, options, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSpace(File file, boolean isOwn) {
|
public void addSource(File source) {
|
||||||
fernflower.getStructContext().addSpace(file, isOwn);
|
engine.addSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLibrary(File library) {
|
||||||
|
engine.addLibrary(library);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decompileContext() {
|
public void decompileContext() {
|
||||||
try {
|
try {
|
||||||
fernflower.decompileContext();
|
engine.decompileContext();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
fernflower.clearContext();
|
engine.clearContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,17 +135,11 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
return InterpreterUtil.getBytes(file);
|
return InterpreterUtil.getBytes(file);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ZipFile archive = new ZipFile(file);
|
try (ZipFile archive = new ZipFile(file)) {
|
||||||
try {
|
|
||||||
ZipEntry entry = archive.getEntry(internalPath);
|
ZipEntry entry = archive.getEntry(internalPath);
|
||||||
if (entry == null) {
|
if (entry == null) throw new IOException("Entry not found: " + internalPath);
|
||||||
throw new IOException("Entry not found: " + internalPath);
|
|
||||||
}
|
|
||||||
return InterpreterUtil.getBytes(archive, entry);
|
return InterpreterUtil.getBytes(archive, entry);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
archive.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,16 +170,10 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
|
public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) {
|
||||||
File file = new File(getAbsolutePath(path), entryName);
|
File file = new File(getAbsolutePath(path), entryName);
|
||||||
try {
|
try (Writer out = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
|
||||||
Writer out = new OutputStreamWriter(new FileOutputStream(file), "UTF8");
|
out.write(content);
|
||||||
try {
|
|
||||||
out.write(content);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
DecompilerContext.getLogger().writeMessage("Cannot write class file " + file, ex);
|
DecompilerContext.getLogger().writeMessage("Cannot write class file " + file, ex);
|
||||||
@ -206,7 +189,6 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FileOutputStream fileStream = new FileOutputStream(file);
|
FileOutputStream fileStream = new FileOutputStream(file);
|
||||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
|
||||||
ZipOutputStream zipStream = manifest != null ? new JarOutputStream(fileStream, manifest) : new ZipOutputStream(fileStream);
|
ZipOutputStream zipStream = manifest != null ? new JarOutputStream(fileStream, manifest) : new ZipOutputStream(fileStream);
|
||||||
mapArchiveStreams.put(file.getPath(), zipStream);
|
mapArchiveStreams.put(file.getPath(), zipStream);
|
||||||
}
|
}
|
||||||
@ -228,21 +210,15 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try (ZipFile srcArchive = new ZipFile(new File(source))) {
|
||||||
ZipFile srcArchive = new ZipFile(new File(source));
|
ZipEntry entry = srcArchive.getEntry(entryName);
|
||||||
try {
|
if (entry != null) {
|
||||||
ZipEntry entry = srcArchive.getEntry(entryName);
|
try (InputStream in = srcArchive.getInputStream(entry)) {
|
||||||
if (entry != null) {
|
|
||||||
InputStream in = srcArchive.getInputStream(entry);
|
|
||||||
ZipOutputStream out = mapArchiveStreams.get(file);
|
ZipOutputStream out = mapArchiveStreams.get(file);
|
||||||
out.putNextEntry(new ZipEntry(entryName));
|
out.putNextEntry(new ZipEntry(entryName));
|
||||||
InterpreterUtil.copyStream(in, out);
|
InterpreterUtil.copyStream(in, out);
|
||||||
in.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
srcArchive.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
String message = "Cannot copy entry " + entryName + " from " + source + " to " + file;
|
String message = "Cannot copy entry " + entryName + " from " + source + " to " + file;
|
||||||
@ -262,7 +238,7 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
ZipOutputStream out = mapArchiveStreams.get(file);
|
ZipOutputStream out = mapArchiveStreams.get(file);
|
||||||
out.putNextEntry(new ZipEntry(entryName));
|
out.putNextEntry(new ZipEntry(entryName));
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
out.write(content.getBytes("UTF-8"));
|
out.write(content.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
@ -272,10 +248,7 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkEntry(String entryName, String file) {
|
private boolean checkEntry(String entryName, String file) {
|
||||||
Set<String> set = mapArchiveEntries.get(file);
|
Set<String> set = mapArchiveEntries.computeIfAbsent(file, k -> new HashSet<>());
|
||||||
if (set == null) {
|
|
||||||
mapArchiveEntries.put(file, set = new HashSet<String>());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean added = set.add(entryName);
|
boolean added = set.add(entryName);
|
||||||
if (!added) {
|
if (!added) {
|
||||||
@ -296,4 +269,4 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
|||||||
DecompilerContext.getLogger().writeMessage("Cannot close " + file, IFernflowerLogger.Severity.WARN);
|
DecompilerContext.getLogger().writeMessage("Cannot close " + file, IFernflowerLogger.Severity.WARN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,22 +1,8 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.decompiler;
|
package org.jetbrains.java.decompiler.main.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||||
|
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
@ -33,62 +19,79 @@ public class PrintStreamLogger extends IFernflowerLogger {
|
|||||||
@Override
|
@Override
|
||||||
public void writeMessage(String message, Severity severity) {
|
public void writeMessage(String message, Severity severity) {
|
||||||
if (accepts(severity)) {
|
if (accepts(severity)) {
|
||||||
stream.println(severity.prefix + InterpreterUtil.getIndentString(indent) + message);
|
stream.println(severity.prefix + TextUtil.getIndentString(indent) + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeMessage(String message, Throwable t) {
|
public void writeMessage(String message, Severity severity, Throwable t) {
|
||||||
writeMessage(message, Severity.ERROR);
|
if (accepts(severity)) {
|
||||||
if (accepts(Severity.ERROR)) {
|
writeMessage(message, severity);
|
||||||
t.printStackTrace(stream);
|
t.printStackTrace(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startReadingClass(String className) {
|
public void startReadingClass(String className) {
|
||||||
writeMessage("Decompiling class " + className, Severity.INFO);
|
if (accepts(Severity.INFO)) {
|
||||||
++indent;
|
writeMessage("Decompiling class " + className, Severity.INFO);
|
||||||
|
++indent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endReadingClass() {
|
public void endReadingClass() {
|
||||||
--indent;
|
if (accepts(Severity.INFO)) {
|
||||||
writeMessage("... done", Severity.INFO);
|
--indent;
|
||||||
|
writeMessage("... done", Severity.INFO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startClass(String className) {
|
public void startClass(String className) {
|
||||||
writeMessage("Processing class " + className, Severity.TRACE);
|
if (accepts(Severity.INFO)) {
|
||||||
++indent;
|
writeMessage("Processing class " + className, Severity.TRACE);
|
||||||
|
++indent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endClass() {
|
public void endClass() {
|
||||||
--indent;
|
if (accepts(Severity.INFO)) {
|
||||||
writeMessage("... proceeded", Severity.TRACE);
|
--indent;
|
||||||
|
writeMessage("... proceeded", Severity.TRACE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startMethod(String methodName) {
|
public void startMethod(String methodName) {
|
||||||
writeMessage("Processing method " + methodName, Severity.TRACE);
|
if (accepts(Severity.INFO)) {
|
||||||
++indent;
|
writeMessage("Processing method " + methodName, Severity.TRACE);
|
||||||
|
++indent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void endMethod() {
|
public void endMethod() {
|
||||||
--indent;
|
if (accepts(Severity.INFO)) {
|
||||||
writeMessage("... proceeded", Severity.TRACE);
|
--indent;
|
||||||
|
writeMessage("... proceeded", Severity.TRACE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startWriteClass(String className) {
|
public void startWriteClass(String className) {
|
||||||
writeMessage("Writing class " + className, Severity.TRACE);
|
if (accepts(Severity.INFO)) {
|
||||||
++indent;
|
writeMessage("Writing class " + className, Severity.TRACE);
|
||||||
|
++indent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endWriteClass() {
|
public void endWriteClass() {
|
||||||
--indent;
|
if (accepts(Severity.INFO)) {
|
||||||
writeMessage("... written", Severity.TRACE);
|
--indent;
|
||||||
|
writeMessage("... written", Severity.TRACE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.extern;
|
package org.jetbrains.java.decompiler.main.extern;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.extern;
|
package org.jetbrains.java.decompiler.main.extern;
|
||||||
|
|
||||||
public abstract class IFernflowerLogger {
|
public abstract class IFernflowerLogger {
|
||||||
@ -39,7 +25,11 @@ public abstract class IFernflowerLogger {
|
|||||||
|
|
||||||
public abstract void writeMessage(String message, Severity severity);
|
public abstract void writeMessage(String message, Severity severity);
|
||||||
|
|
||||||
public abstract void writeMessage(String message, Throwable t);
|
public abstract void writeMessage(String message, Severity severity, Throwable t);
|
||||||
|
|
||||||
|
public void writeMessage(String message, Throwable t) {
|
||||||
|
writeMessage(message, Severity.ERROR, t);
|
||||||
|
}
|
||||||
|
|
||||||
public void startReadingClass(String className) { }
|
public void startReadingClass(String className) { }
|
||||||
|
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.extern;
|
package org.jetbrains.java.decompiler.main.extern;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
@ -31,6 +17,7 @@ public interface IFernflowerPreferences {
|
|||||||
String HIDE_DEFAULT_CONSTRUCTOR = "hdc";
|
String HIDE_DEFAULT_CONSTRUCTOR = "hdc";
|
||||||
String DECOMPILE_GENERIC_SIGNATURES = "dgs";
|
String DECOMPILE_GENERIC_SIGNATURES = "dgs";
|
||||||
String NO_EXCEPTIONS_RETURN = "ner";
|
String NO_EXCEPTIONS_RETURN = "ner";
|
||||||
|
String ENSURE_SYNCHRONIZED_MONITOR = "esm";
|
||||||
String DECOMPILE_ENUM = "den";
|
String DECOMPILE_ENUM = "den";
|
||||||
String REMOVE_GET_CLASS_NEW = "rgn";
|
String REMOVE_GET_CLASS_NEW = "rgn";
|
||||||
String LITERALS_AS_IS = "lit";
|
String LITERALS_AS_IS = "lit";
|
||||||
@ -39,13 +26,14 @@ public interface IFernflowerPreferences {
|
|||||||
String SYNTHETIC_NOT_SET = "nns";
|
String SYNTHETIC_NOT_SET = "nns";
|
||||||
String UNDEFINED_PARAM_TYPE_OBJECT = "uto";
|
String UNDEFINED_PARAM_TYPE_OBJECT = "uto";
|
||||||
String USE_DEBUG_VAR_NAMES = "udv";
|
String USE_DEBUG_VAR_NAMES = "udv";
|
||||||
|
String USE_METHOD_PARAMETERS = "ump";
|
||||||
String REMOVE_EMPTY_RANGES = "rer";
|
String REMOVE_EMPTY_RANGES = "rer";
|
||||||
String FINALLY_DEINLINE = "fdi";
|
String FINALLY_DEINLINE = "fdi";
|
||||||
String IDEA_NOT_NULL_ANNOTATION = "inn";
|
String IDEA_NOT_NULL_ANNOTATION = "inn";
|
||||||
String LAMBDA_TO_ANONYMOUS_CLASS = "lac";
|
String LAMBDA_TO_ANONYMOUS_CLASS = "lac";
|
||||||
|
|
||||||
String BYTECODE_SOURCE_MAPPING = "bsm";
|
String BYTECODE_SOURCE_MAPPING = "bsm";
|
||||||
String USE_DEBUG_LINE_NUMBERS = "udl";
|
String IGNORE_INVALID_BYTECODE = "iib";
|
||||||
|
String VERIFY_ANONYMOUS_CLASSES = "vac";
|
||||||
|
|
||||||
String LOG_LEVEL = "log";
|
String LOG_LEVEL = "log";
|
||||||
String MAX_PROCESSING_METHOD = "mpm";
|
String MAX_PROCESSING_METHOD = "mpm";
|
||||||
@ -53,44 +41,55 @@ public interface IFernflowerPreferences {
|
|||||||
String USER_RENAMER_CLASS = "urc";
|
String USER_RENAMER_CLASS = "urc";
|
||||||
String NEW_LINE_SEPARATOR = "nls";
|
String NEW_LINE_SEPARATOR = "nls";
|
||||||
String INDENT_STRING = "ind";
|
String INDENT_STRING = "ind";
|
||||||
|
|
||||||
String BANNER = "ban";
|
String BANNER = "ban";
|
||||||
|
|
||||||
|
String DUMP_ORIGINAL_LINES = "__dump_original_lines__";
|
||||||
|
String UNIT_TEST_MODE = "__unit_test_mode__";
|
||||||
|
|
||||||
String LINE_SEPARATOR_WIN = "\r\n";
|
String LINE_SEPARATOR_WIN = "\r\n";
|
||||||
String LINE_SEPARATOR_LIN = "\n";
|
String LINE_SEPARATOR_UNX = "\n";
|
||||||
|
|
||||||
Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>() {{
|
Map<String, Object> DEFAULTS = getDefaults();
|
||||||
put(REMOVE_BRIDGE, "1");
|
|
||||||
put(REMOVE_SYNTHETIC, "0");
|
|
||||||
put(DECOMPILE_INNER, "1");
|
|
||||||
put(DECOMPILE_CLASS_1_4, "1");
|
|
||||||
put(DECOMPILE_ASSERTIONS, "1");
|
|
||||||
put(HIDE_EMPTY_SUPER, "1");
|
|
||||||
put(HIDE_DEFAULT_CONSTRUCTOR, "1");
|
|
||||||
put(DECOMPILE_GENERIC_SIGNATURES, "0");
|
|
||||||
put(NO_EXCEPTIONS_RETURN, "1");
|
|
||||||
put(DECOMPILE_ENUM, "1");
|
|
||||||
put(REMOVE_GET_CLASS_NEW, "1");
|
|
||||||
put(LITERALS_AS_IS, "0");
|
|
||||||
put(BOOLEAN_TRUE_ONE, "1");
|
|
||||||
put(ASCII_STRING_CHARACTERS, "0");
|
|
||||||
put(SYNTHETIC_NOT_SET, "1");
|
|
||||||
put(UNDEFINED_PARAM_TYPE_OBJECT, "1");
|
|
||||||
put(USE_DEBUG_VAR_NAMES, "1");
|
|
||||||
put(REMOVE_EMPTY_RANGES, "1");
|
|
||||||
put(FINALLY_DEINLINE, "1");
|
|
||||||
put(IDEA_NOT_NULL_ANNOTATION, "1");
|
|
||||||
put(LAMBDA_TO_ANONYMOUS_CLASS, "0");
|
|
||||||
|
|
||||||
put(BYTECODE_SOURCE_MAPPING, "0");
|
static Map<String, Object> getDefaults() {
|
||||||
put(USE_DEBUG_LINE_NUMBERS, "0");
|
Map<String, Object> defaults = new HashMap<>();
|
||||||
|
|
||||||
put(BANNER, "");
|
defaults.put(REMOVE_BRIDGE, "1");
|
||||||
|
defaults.put(REMOVE_SYNTHETIC, "0");
|
||||||
|
defaults.put(DECOMPILE_INNER, "1");
|
||||||
|
defaults.put(DECOMPILE_CLASS_1_4, "1");
|
||||||
|
defaults.put(DECOMPILE_ASSERTIONS, "1");
|
||||||
|
defaults.put(HIDE_EMPTY_SUPER, "1");
|
||||||
|
defaults.put(HIDE_DEFAULT_CONSTRUCTOR, "1");
|
||||||
|
defaults.put(DECOMPILE_GENERIC_SIGNATURES, "0");
|
||||||
|
defaults.put(NO_EXCEPTIONS_RETURN, "1");
|
||||||
|
defaults.put(ENSURE_SYNCHRONIZED_MONITOR, "1");
|
||||||
|
defaults.put(DECOMPILE_ENUM, "1");
|
||||||
|
defaults.put(REMOVE_GET_CLASS_NEW, "1");
|
||||||
|
defaults.put(LITERALS_AS_IS, "0");
|
||||||
|
defaults.put(BOOLEAN_TRUE_ONE, "1");
|
||||||
|
defaults.put(ASCII_STRING_CHARACTERS, "0");
|
||||||
|
defaults.put(SYNTHETIC_NOT_SET, "0");
|
||||||
|
defaults.put(UNDEFINED_PARAM_TYPE_OBJECT, "1");
|
||||||
|
defaults.put(USE_DEBUG_VAR_NAMES, "1");
|
||||||
|
defaults.put(USE_METHOD_PARAMETERS, "1");
|
||||||
|
defaults.put(REMOVE_EMPTY_RANGES, "1");
|
||||||
|
defaults.put(FINALLY_DEINLINE, "1");
|
||||||
|
defaults.put(IDEA_NOT_NULL_ANNOTATION, "1");
|
||||||
|
defaults.put(LAMBDA_TO_ANONYMOUS_CLASS, "0");
|
||||||
|
defaults.put(BYTECODE_SOURCE_MAPPING, "0");
|
||||||
|
defaults.put(IGNORE_INVALID_BYTECODE, "0");
|
||||||
|
defaults.put(VERIFY_ANONYMOUS_CLASSES, "0");
|
||||||
|
|
||||||
put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name());
|
defaults.put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name());
|
||||||
put(MAX_PROCESSING_METHOD, "0");
|
defaults.put(MAX_PROCESSING_METHOD, "0");
|
||||||
put(RENAME_ENTITIES, "0");
|
defaults.put(RENAME_ENTITIES, "0");
|
||||||
put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1"));
|
defaults.put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1"));
|
||||||
put(INDENT_STRING, " ");
|
defaults.put(INDENT_STRING, " ");
|
||||||
}});
|
defaults.put(BANNER, "");
|
||||||
}
|
defaults.put(UNIT_TEST_MODE, "0");
|
||||||
|
defaults.put(DUMP_ORIGINAL_LINES, "0");
|
||||||
|
|
||||||
|
return Collections.unmodifiableMap(defaults);
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +1,15 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.extern;
|
package org.jetbrains.java.decompiler.main.extern;
|
||||||
|
|
||||||
|
|
||||||
public interface IIdentifierRenamer {
|
public interface IIdentifierRenamer {
|
||||||
|
|
||||||
int ELEMENT_CLASS = 1;
|
enum Type {ELEMENT_CLASS, ELEMENT_FIELD, ELEMENT_METHOD}
|
||||||
|
|
||||||
int ELEMENT_FIELD = 2;
|
boolean toBeRenamed(Type elementType, String className, String element, String descriptor);
|
||||||
|
|
||||||
int ELEMENT_METHOD = 3;
|
String getNextClassName(String fullName, String shortName);
|
||||||
|
|
||||||
|
String getNextFieldName(String className, String field, String descriptor);
|
||||||
|
|
||||||
boolean toBeRenamed(int element_type, String classname, String element, String descriptor);
|
String getNextMethodName(String className, String method, String descriptor);
|
||||||
|
|
||||||
String getNextClassname(String fullname, String shortname);
|
|
||||||
|
|
||||||
String getNextFieldname(String classname, String field, String descriptor);
|
|
||||||
|
|
||||||
String getNextMethodname(String classname, String method, String descriptor);
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.extern;
|
package org.jetbrains.java.decompiler.main.extern;
|
||||||
|
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
@ -22,7 +8,7 @@ public interface IResultSaver {
|
|||||||
|
|
||||||
void copyFile(String source, String path, String entryName);
|
void copyFile(String source, String path, String entryName);
|
||||||
|
|
||||||
void saveClassFile(String path, String qualifiedName, String entryName, String content);
|
void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping);
|
||||||
|
|
||||||
void createArchive(String path, String archiveName, Manifest manifest);
|
void createArchive(String path, String archiveName, Manifest manifest);
|
||||||
|
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.rels;
|
package org.jetbrains.java.decompiler.main.rels;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -22,64 +8,49 @@ import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
|
|||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructField;
|
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
|
||||||
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
|
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ClassWrapper {
|
public class ClassWrapper {
|
||||||
|
private final StructClass classStruct;
|
||||||
private StructClass classStruct;
|
private final Set<String> hiddenMembers = new HashSet<>();
|
||||||
private Set<String> hiddenMembers = new HashSet<String>();
|
private final VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<>();
|
||||||
private VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<Exprent, String>();
|
private final VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<>();
|
||||||
private VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<Exprent, String>();
|
private final VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<>();
|
||||||
private VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<MethodWrapper, String>();
|
|
||||||
|
|
||||||
|
|
||||||
public ClassWrapper(StructClass classStruct) {
|
public ClassWrapper(StructClass classStruct) {
|
||||||
this.classStruct = classStruct;
|
this.classStruct = classStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() throws IOException {
|
public void init() {
|
||||||
|
|
||||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
|
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
|
||||||
|
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_WRAPPER, this);
|
||||||
DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
|
DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
|
||||||
|
|
||||||
// collect field names
|
int maxSec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
|
||||||
HashSet<String> setFieldNames = new HashSet<String>();
|
boolean testMode = DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE);
|
||||||
for (StructField fd : classStruct.getFields()) {
|
|
||||||
setFieldNames.add(fd.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
int maxsec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
|
|
||||||
|
|
||||||
for (StructMethod mt : classStruct.getMethods()) {
|
for (StructMethod mt : classStruct.getMethods()) {
|
||||||
|
|
||||||
DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
|
DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
|
||||||
|
|
||||||
VarNamesCollector vc = new VarNamesCollector();
|
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
||||||
DecompilerContext.setVarNamesCollector(vc);
|
VarProcessor varProc = new VarProcessor(mt, md);
|
||||||
|
DecompilerContext.startMethod(varProc);
|
||||||
|
|
||||||
CounterContainer counter = new CounterContainer();
|
VarNamesCollector vc = varProc.getVarNamesCollector();
|
||||||
DecompilerContext.setCounterContainer(counter);
|
CounterContainer counter = DecompilerContext.getCounterContainer();
|
||||||
|
|
||||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD, mt);
|
|
||||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR, MethodDescriptor.parseDescriptor(mt.getDescriptor()));
|
|
||||||
|
|
||||||
VarProcessor varproc = new VarProcessor();
|
|
||||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varproc);
|
|
||||||
|
|
||||||
RootStatement root = null;
|
RootStatement root = null;
|
||||||
|
|
||||||
@ -87,86 +58,113 @@ public class ClassWrapper {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (mt.containsCode()) {
|
if (mt.containsCode()) {
|
||||||
|
if (maxSec == 0 || testMode) {
|
||||||
if (maxsec == 0) { // blocking wait
|
root = MethodProcessorRunnable.codeToJava(classStruct, mt, md, varProc);
|
||||||
root = MethodProcessorThread.codeToJava(mt, varproc);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MethodProcessorThread mtproc = new MethodProcessorThread(mt, varproc, DecompilerContext.getCurrentContext());
|
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(classStruct, mt, md, varProc, DecompilerContext.getCurrentContext());
|
||||||
Thread mtthread = new Thread(mtproc);
|
|
||||||
long stopAt = System.currentTimeMillis() + maxsec * 1000;
|
|
||||||
|
|
||||||
mtthread.start();
|
Thread mtThread = new Thread(mtProc, "Java decompiler");
|
||||||
|
long stopAt = System.currentTimeMillis() + maxSec * 1000L;
|
||||||
|
|
||||||
while (mtthread.isAlive()) {
|
mtThread.start();
|
||||||
|
|
||||||
synchronized (mtproc.lock) {
|
while (!mtProc.isFinished()) {
|
||||||
mtproc.lock.wait(100);
|
try {
|
||||||
|
synchronized (mtProc.lock) {
|
||||||
|
mtProc.lock.wait(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
killThread(mtThread);
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (System.currentTimeMillis() >= stopAt) {
|
if (System.currentTimeMillis() >= stopAt) {
|
||||||
String message = "Processing time limit exceeded for method " + mt.getName() + ", execution interrupted.";
|
String message = "Processing time limit exceeded for method " + mt.getName() + ", execution interrupted.";
|
||||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR);
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR);
|
||||||
killThread(mtthread);
|
killThread(mtThread);
|
||||||
isError = true;
|
isError = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isError) {
|
if (!isError) {
|
||||||
root = mtproc.getResult();
|
root = mtProc.getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
||||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
|
||||||
|
|
||||||
int paramcount = 0;
|
int paramCount = 0;
|
||||||
if (thisvar) {
|
if (thisVar) {
|
||||||
varproc.getThisvars().put(new VarVersionPaar(0, 0), classStruct.qualifiedName);
|
varProc.getThisVars().put(new VarVersionPair(0, 0), classStruct.qualifiedName);
|
||||||
paramcount = 1;
|
paramCount = 1;
|
||||||
}
|
}
|
||||||
paramcount += md.params.length;
|
paramCount += md.params.length;
|
||||||
|
|
||||||
int varindex = 0;
|
int varIndex = 0;
|
||||||
for (int i = 0; i < paramcount; i++) {
|
for (int i = 0; i < paramCount; i++) {
|
||||||
varproc.setVarName(new VarVersionPaar(varindex, 0, classStruct.qualifiedName, false), vc.getFreeName(varindex));
|
varProc.setVarName(new VarVersionPair(varIndex, 0), "tbd");//, vc.getFreeName(varIndex));
|
||||||
|
|
||||||
if (thisvar) {
|
if (thisVar) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
varindex++;
|
varIndex++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
varindex += md.params[i - 1].stack_size;
|
varProc.setVarName(new VarVersionPair(varIndex, 0), vc.getTypeLabel(md.params[i - 1], varIndex));
|
||||||
|
varIndex += md.params[i - 1].stackSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
varindex += md.params[i].stack_size;
|
varProc.setVarName(new VarVersionPair(varIndex, 0), vc.getTypeLabel(md.params[i], varIndex));
|
||||||
|
varIndex += md.params[i].stackSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable t) {
|
||||||
DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.", ex);
|
String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.";
|
||||||
|
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, t);
|
||||||
isError = true;
|
isError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodWrapper meth = new MethodWrapper(root, varproc, mt, counter);
|
MethodWrapper methodWrapper = new MethodWrapper(root, varProc, mt, counter);
|
||||||
meth.decompiledWithErrors = isError;
|
methodWrapper.decompiledWithErrors = isError;
|
||||||
|
|
||||||
methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
|
methods.addWithKey(methodWrapper, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
|
||||||
|
|
||||||
// rename vars so that no one has the same name as a field
|
if (!isError) {
|
||||||
varproc.refreshVarNames(new VarNamesCollector(setFieldNames));
|
// rename vars so that no one has the same name as a field
|
||||||
|
VarNamesCollector namesCollector = new VarNamesCollector();
|
||||||
|
// well, actually, no -reece
|
||||||
|
//classStruct.getFields().forEach(f -> namesCollector.addName(f.getName()));
|
||||||
|
varProc.refreshVarNames(namesCollector);
|
||||||
|
|
||||||
// if debug information present and should be used
|
// if debug information present and should be used
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
||||||
StructLocalVariableTableAttribute attr = (StructLocalVariableTableAttribute)mt.getAttributes().getWithKey(
|
StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr();
|
||||||
StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE);
|
if (attr != null) {
|
||||||
|
// only param names here
|
||||||
|
varProc.setDebugVarNames(attr.getMapParamNames());
|
||||||
|
|
||||||
if (attr != null) {
|
// the rest is here
|
||||||
varproc.setDebugVarNames(attr.getMapVarNames());
|
methodWrapper.getOrBuildGraph().iterateExprents(exprent -> {
|
||||||
|
List<Exprent> lst = exprent.getAllExprents(true);
|
||||||
|
lst.add(exprent);
|
||||||
|
lst.stream()
|
||||||
|
.filter(e -> e.type == Exprent.EXPRENT_VAR)
|
||||||
|
.forEach(e -> {
|
||||||
|
VarExprent varExprent = (VarExprent)e;
|
||||||
|
String name = varExprent.getDebugName(mt);
|
||||||
|
if (name != null) {
|
||||||
|
varProc.setVarName(varExprent.getVarVersionPair(), name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,4 +202,9 @@ public class ClassWrapper {
|
|||||||
public VBStyleCollection<Exprent, String> getDynamicFieldInitializers() {
|
public VBStyleCollection<Exprent, String> getDynamicFieldInitializers() {
|
||||||
return dynamicFieldInitializers;
|
return dynamicFieldInitializers;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return classStruct.qualifiedName;
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.rels;
|
package org.jetbrains.java.decompiler.main.rels;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -35,36 +21,28 @@ import java.io.IOException;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class LambdaProcessor {
|
public class LambdaProcessor {
|
||||||
|
|
||||||
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory";
|
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory";
|
||||||
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_METHOD = "metafactory";
|
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_METHOD = "metafactory";
|
||||||
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_ALT_METHOD = "altMetafactory";
|
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_ALT_METHOD = "altMetafactory";
|
||||||
|
|
||||||
public void processClass(ClassNode node) throws IOException {
|
public void processClass(ClassNode node) throws IOException {
|
||||||
|
|
||||||
for (ClassNode child : node.nested) {
|
for (ClassNode child : node.nested) {
|
||||||
processClass(child);
|
processClass(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLambda(node);
|
ClassesProcessor clProcessor = DecompilerContext.getClassProcessor();
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasLambda(ClassNode node) throws IOException {
|
|
||||||
|
|
||||||
ClassesProcessor clprocessor = DecompilerContext.getClassProcessor();
|
|
||||||
StructClass cl = node.classStruct;
|
StructClass cl = node.classStruct;
|
||||||
|
|
||||||
if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lamda beginning with Java 8
|
if (!cl.isVersion8()) { // lambda beginning with Java 8
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StructBootstrapMethodsAttribute bootstrap =
|
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
||||||
(StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
|
||||||
if (bootstrap == null || bootstrap.getMethodsNumber() == 0) {
|
if (bootstrap == null || bootstrap.getMethodsNumber() == 0) {
|
||||||
return false; // no bootstrap constants in pool
|
return; // no bootstrap constants in pool
|
||||||
}
|
}
|
||||||
|
|
||||||
BitSet lambda_methods = new BitSet();
|
BitSet lambdaMethods = new BitSet();
|
||||||
|
|
||||||
// find lambda bootstrap constants
|
// find lambda bootstrap constants
|
||||||
for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
|
for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
|
||||||
@ -73,19 +51,19 @@ public class LambdaProcessor {
|
|||||||
// FIXME: extend for Eclipse etc. at some point
|
// FIXME: extend for Eclipse etc. at some point
|
||||||
if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
|
if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
|
||||||
(JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) || JAVAC_LAMBDA_ALT_METHOD.equals(method_ref.elementname))) {
|
(JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) || JAVAC_LAMBDA_ALT_METHOD.equals(method_ref.elementname))) {
|
||||||
lambda_methods.set(i);
|
lambdaMethods.set(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lambda_methods.isEmpty()) {
|
if (lambdaMethods.isEmpty()) {
|
||||||
return false; // no lambda bootstrap constant found
|
return; // no lambda bootstrap constant found
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> mapMethodsLambda = new HashMap<String, String>();
|
Map<String, String> mapMethodsLambda = new HashMap<>();
|
||||||
|
|
||||||
// iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
|
// iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
|
||||||
for (StructMethod mt : cl.getMethods()) {
|
for (StructMethod mt : cl.getMethods()) {
|
||||||
mt.expandData();
|
mt.expandData(cl);
|
||||||
|
|
||||||
InstructionSequence seq = mt.getInstructionSequence();
|
InstructionSequence seq = mt.getInstructionSequence();
|
||||||
if (seq != null && seq.length() > 0) {
|
if (seq != null && seq.length() > 0) {
|
||||||
@ -95,9 +73,9 @@ public class LambdaProcessor {
|
|||||||
Instruction instr = seq.getInstr(i);
|
Instruction instr = seq.getInstr(i);
|
||||||
|
|
||||||
if (instr.opcode == CodeConstants.opc_invokedynamic) {
|
if (instr.opcode == CodeConstants.opc_invokedynamic) {
|
||||||
LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0));
|
LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.operand(0));
|
||||||
|
|
||||||
if (lambda_methods.get(invoke_dynamic.index1)) { // lambda invocation found
|
if (lambdaMethods.get(invoke_dynamic.index1)) { // lambda invocation found
|
||||||
|
|
||||||
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
|
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
|
||||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
|
MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
|
||||||
@ -117,9 +95,9 @@ public class LambdaProcessor {
|
|||||||
node.nested.add(node_lambda);
|
node.nested.add(node_lambda);
|
||||||
node_lambda.parent = node;
|
node_lambda.parent = node;
|
||||||
|
|
||||||
clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
|
clProcessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
|
||||||
if (!node_lambda.lambda_information.is_method_reference) {
|
if (!node_lambda.lambdaInformation.is_method_reference) {
|
||||||
mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName);
|
mapMethodsLambda.put(node_lambda.lambdaInformation.content_method_key, node_lambda.simpleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +112,7 @@ public class LambdaProcessor {
|
|||||||
if (nd.type == ClassNode.CLASS_LAMBDA) {
|
if (nd.type == ClassNode.CLASS_LAMBDA) {
|
||||||
String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
|
String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
|
||||||
if (parent_class_name != null) {
|
if (parent_class_name != null) {
|
||||||
ClassNode parent_class = clprocessor.getMapRootClasses().get(parent_class_name);
|
ClassNode parent_class = clProcessor.getMapRootClasses().get(parent_class_name);
|
||||||
|
|
||||||
parent_class.nested.add(nd);
|
parent_class.nested.add(nd);
|
||||||
nd.parent = parent_class;
|
nd.parent = parent_class;
|
||||||
@ -143,7 +121,5 @@ public class LambdaProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: mixed hierarchy?
|
// FIXME: mixed hierarchy?
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,7 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.rels;
|
package org.jetbrains.java.decompiler.main.rels;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
@ -28,81 +15,73 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass;
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class MethodProcessorThread implements Runnable {
|
public class MethodProcessorRunnable implements Runnable {
|
||||||
|
|
||||||
public final Object lock = new Object();
|
public final Object lock = new Object();
|
||||||
|
|
||||||
|
private final StructClass klass;
|
||||||
private final StructMethod method;
|
private final StructMethod method;
|
||||||
private final VarProcessor varproc;
|
private final MethodDescriptor methodDescriptor;
|
||||||
|
private final VarProcessor varProc;
|
||||||
private final DecompilerContext parentContext;
|
private final DecompilerContext parentContext;
|
||||||
|
|
||||||
private volatile RootStatement root;
|
private volatile RootStatement root;
|
||||||
private volatile Throwable error;
|
private volatile Throwable error;
|
||||||
|
private volatile boolean finished = false;
|
||||||
|
|
||||||
public MethodProcessorThread(StructMethod method, VarProcessor varproc, DecompilerContext parentContext) {
|
public MethodProcessorRunnable(StructClass klass,
|
||||||
|
StructMethod method,
|
||||||
|
MethodDescriptor methodDescriptor,
|
||||||
|
VarProcessor varProc,
|
||||||
|
DecompilerContext parentContext) {
|
||||||
|
this.klass = klass;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.varproc = varproc;
|
this.methodDescriptor = methodDescriptor;
|
||||||
|
this.varProc = varProc;
|
||||||
this.parentContext = parentContext;
|
this.parentContext = parentContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
DecompilerContext.setCurrentContext(parentContext);
|
|
||||||
|
|
||||||
error = null;
|
error = null;
|
||||||
root = null;
|
root = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
root = codeToJava(method, varproc);
|
DecompilerContext.setCurrentContext(parentContext);
|
||||||
|
root = codeToJava(klass, method, methodDescriptor, varProc);
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
error = t;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
DecompilerContext.setCurrentContext(null);
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (lock) {
|
finished = true;
|
||||||
lock.notifyAll();
|
synchronized (lock) {
|
||||||
}
|
lock.notifyAll();
|
||||||
}
|
|
||||||
catch (ThreadDeath ex) {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
error = ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RootStatement codeToJava(StructMethod mt, VarProcessor varproc) throws IOException {
|
public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDescriptor md, VarProcessor varProc) throws IOException {
|
||||||
|
boolean isInitializer = CodeConstants.CLINIT_NAME.equals(mt.getName()); // for now static initializer only
|
||||||
|
|
||||||
StructClass cl = mt.getClassStruct();
|
mt.expandData(cl);
|
||||||
|
|
||||||
boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
|
|
||||||
|
|
||||||
mt.expandData();
|
|
||||||
InstructionSequence seq = mt.getInstructionSequence();
|
InstructionSequence seq = mt.getInstructionSequence();
|
||||||
ControlFlowGraph graph = new ControlFlowGraph(seq);
|
ControlFlowGraph graph = new ControlFlowGraph(seq);
|
||||||
|
|
||||||
// System.out.println(graph.toString());
|
|
||||||
|
|
||||||
|
|
||||||
// if(mt.getName().endsWith("_getActiveServers")) {
|
|
||||||
// System.out.println();
|
|
||||||
// }
|
|
||||||
|
|
||||||
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true);
|
|
||||||
|
|
||||||
DeadCodeHelper.removeDeadBlocks(graph);
|
DeadCodeHelper.removeDeadBlocks(graph);
|
||||||
graph.inlineJsr(mt);
|
graph.inlineJsr(cl, mt);
|
||||||
|
|
||||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern4.dot"), true);
|
|
||||||
|
|
||||||
// TODO: move to the start, before jsr inlining
|
// TODO: move to the start, before jsr inlining
|
||||||
DeadCodeHelper.connectDummyExitBlock(graph);
|
DeadCodeHelper.connectDummyExitBlock(graph);
|
||||||
|
|
||||||
DeadCodeHelper.removeGotos(graph);
|
DeadCodeHelper.removeGotos(graph);
|
||||||
|
|
||||||
ExceptionDeobfuscator.removeCircularRanges(graph);
|
ExceptionDeobfuscator.removeCircularRanges(graph);
|
||||||
//DeadCodeHelper.removeCircularRanges(graph);
|
|
||||||
|
|
||||||
|
|
||||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
||||||
|
|
||||||
ExceptionDeobfuscator.restorePopRanges(graph);
|
ExceptionDeobfuscator.restorePopRanges(graph);
|
||||||
|
|
||||||
@ -110,15 +89,16 @@ public class MethodProcessorThread implements Runnable {
|
|||||||
ExceptionDeobfuscator.removeEmptyRanges(graph);
|
ExceptionDeobfuscator.removeEmptyRanges(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
if (DecompilerContext.getOption(IFernflowerPreferences.ENSURE_SYNCHRONIZED_MONITOR)) {
|
||||||
|
// special case: search for 'synchronized' ranges w/o monitorexit instruction (as generated by Kotlin and Scala)
|
||||||
|
DeadCodeHelper.extendSynchronizedRangeToMonitorexit(graph);
|
||||||
|
}
|
||||||
|
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {
|
if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {
|
||||||
// special case: single return instruction outside of a protected range
|
// special case: single return instruction outside of a protected range
|
||||||
DeadCodeHelper.incorporateValueReturns(graph);
|
DeadCodeHelper.incorporateValueReturns(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
|
|
||||||
|
|
||||||
// ExceptionDeobfuscator.restorePopRanges(graph);
|
// ExceptionDeobfuscator.restorePopRanges(graph);
|
||||||
ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);
|
ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);
|
||||||
|
|
||||||
@ -126,22 +106,18 @@ 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);
|
|
||||||
//System.out.println(graph.toString());
|
|
||||||
|
|
||||||
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
|
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
|
||||||
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);
|
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);
|
||||||
|
if (!ExceptionDeobfuscator.handleMultipleEntryExceptionRanges(graph)) {
|
||||||
|
DecompilerContext.getLogger().writeMessage("Found multiple entry exception ranges which could not be splitted", IFernflowerLogger.Severity.WARN);
|
||||||
|
}
|
||||||
|
ExceptionDeobfuscator.insertDummyExceptionHandlerBlocks(graph, mt.getBytecodeVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
RootStatement root = DomHelper.parseGraph(graph);
|
RootStatement root = DomHelper.parseGraph(graph);
|
||||||
|
|
||||||
FinallyProcessor fproc = new FinallyProcessor(varproc);
|
FinallyProcessor fProc = new FinallyProcessor(md, varProc);
|
||||||
while (fproc.iterateGraph(mt, root, graph)) {
|
while (fProc.iterateGraph(cl, mt, root, graph)) {
|
||||||
|
|
||||||
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true);
|
|
||||||
//System.out.println(graph.toString());
|
|
||||||
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
||||||
|
|
||||||
root = DomHelper.parseGraph(graph);
|
root = DomHelper.parseGraph(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,72 +125,43 @@ public class MethodProcessorThread implements Runnable {
|
|||||||
// not until now because of comparison between synchronized statements in the finally cycle
|
// not until now because of comparison between synchronized statements in the finally cycle
|
||||||
DomHelper.removeSynchronizedHandler(root);
|
DomHelper.removeSynchronizedHandler(root);
|
||||||
|
|
||||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
||||||
// System.out.println(graph.toString());
|
|
||||||
|
|
||||||
// LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
// LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
||||||
|
|
||||||
SequenceHelper.condenseSequences(root);
|
SequenceHelper.condenseSequences(root);
|
||||||
|
|
||||||
ClearStructHelper.clearStatements(root);
|
ClearStructHelper.clearStatements(root);
|
||||||
|
|
||||||
ExprProcessor proc = new ExprProcessor();
|
ExprProcessor proc = new ExprProcessor(md, varProc);
|
||||||
proc.processStatement(root, cl);
|
proc.processStatement(root, cl);
|
||||||
|
|
||||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
SequenceHelper.condenseSequences(root);
|
||||||
// System.out.println(graph.toString());
|
|
||||||
|
|
||||||
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
StackVarsProcessor stackProc = new StackVarsProcessor();
|
||||||
|
|
||||||
while (true) {
|
do {
|
||||||
StackVarsProcessor stackproc = new StackVarsProcessor();
|
stackProc.simplifyStackVars(root, mt, cl);
|
||||||
stackproc.simplifyStackVars(root, mt, cl);
|
varProc.setVarVersions(root);
|
||||||
|
|
||||||
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
||||||
|
|
||||||
varproc.setVarVersions(root);
|
|
||||||
|
|
||||||
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
||||||
|
|
||||||
if (!new PPandMMHelper().findPPandMM(root)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
while (new PPandMMHelper().findPPandMM(root));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
LabelHelper.cleanUpEdges(root);
|
LabelHelper.cleanUpEdges(root);
|
||||||
|
|
||||||
while (true) {
|
do {
|
||||||
|
|
||||||
MergeHelper.enhanceLoops(root);
|
MergeHelper.enhanceLoops(root);
|
||||||
|
|
||||||
if (LoopExtractHelper.extractLoops(root)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IfHelper.mergeAllIfs(root)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
while (LoopExtractHelper.extractLoops(root) || IfHelper.mergeAllIfs(root));
|
||||||
|
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {
|
if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {
|
||||||
|
|
||||||
if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
|
if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
|
||||||
|
|
||||||
SequenceHelper.condenseSequences(root);
|
SequenceHelper.condenseSequences(root);
|
||||||
|
stackProc.simplifyStackVars(root, mt, cl);
|
||||||
StackVarsProcessor stackproc = new StackVarsProcessor();
|
varProc.setVarVersions(root);
|
||||||
stackproc.simplifyStackVars(root, mt, cl);
|
|
||||||
|
|
||||||
varproc.setVarVersions(root);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelHelper.identifyLabels(root);
|
LabelHelper.identifyLabels(root);
|
||||||
|
|
||||||
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
||||||
|
|
||||||
if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {
|
if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -225,16 +172,16 @@ public class MethodProcessorThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: !!
|
// FIXME: !!
|
||||||
// if(!EliminateLoopsHelper.eliminateLoops(root)) {
|
//if(!EliminateLoopsHelper.eliminateLoops(root)) {
|
||||||
// break;
|
// break;
|
||||||
// }
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitHelper.removeRedundantReturns(root);
|
ExitHelper.removeRedundantReturns(root);
|
||||||
|
|
||||||
SecondaryFunctionsHelper.identifySecondaryFunctions(root);
|
SecondaryFunctionsHelper.identifySecondaryFunctions(root, varProc);
|
||||||
|
|
||||||
varproc.setVarDefinitions(root);
|
varProc.setVarDefinitions(root);
|
||||||
|
|
||||||
// must be the last invocation, because it makes the statement structure inconsistent
|
// must be the last invocation, because it makes the statement structure inconsistent
|
||||||
// FIXME: new edge type needed
|
// FIXME: new edge type needed
|
||||||
@ -242,8 +189,6 @@ public class MethodProcessorThread implements Runnable {
|
|||||||
|
|
||||||
mt.releaseResources();
|
mt.releaseResources();
|
||||||
|
|
||||||
// System.out.println("++++++++++++++++++++++/// \r\n"+root.toJava());
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +198,7 @@ public class MethodProcessorThread implements Runnable {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Throwable getError() {
|
public boolean isFinished() {
|
||||||
return error;
|
return finished;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.rels;
|
package org.jetbrains.java.decompiler.main.rels;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
||||||
@ -20,31 +6,24 @@ import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
|
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class MethodWrapper {
|
public class MethodWrapper {
|
||||||
|
public final RootStatement root;
|
||||||
public RootStatement root;
|
public final VarProcessor varproc;
|
||||||
|
public final StructMethod methodStruct;
|
||||||
public VarProcessor varproc;
|
public final CounterContainer counter;
|
||||||
|
public final Set<String> setOuterVarNames = new HashSet<>();
|
||||||
public StructMethod methodStruct;
|
|
||||||
|
|
||||||
public CounterContainer counter;
|
|
||||||
|
|
||||||
public DirectGraph graph;
|
public DirectGraph graph;
|
||||||
|
public List<VarVersionPair> synthParameters;
|
||||||
public List<VarVersionPaar> signatureFields;
|
|
||||||
|
|
||||||
public boolean decompiledWithErrors;
|
public boolean decompiledWithErrors;
|
||||||
|
|
||||||
public HashSet<String> setOuterVarNames = new HashSet<String>();
|
|
||||||
|
|
||||||
public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {
|
public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.varproc = varproc;
|
this.varproc = varproc;
|
||||||
@ -54,9 +33,13 @@ public class MethodWrapper {
|
|||||||
|
|
||||||
public DirectGraph getOrBuildGraph() {
|
public DirectGraph getOrBuildGraph() {
|
||||||
if (graph == null && root != null) {
|
if (graph == null && root != null) {
|
||||||
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
graph = new FlattenStatementsHelper().buildDirectGraph(root);
|
||||||
graph = flatthelper.buildDirectGraph(root);
|
|
||||||
}
|
}
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return methodStruct.getName();
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.main.rels;
|
package org.jetbrains.java.decompiler.main.rels;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -24,25 +10,19 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
|
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
|
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class NestedMemberAccess {
|
public class NestedMemberAccess {
|
||||||
|
|
||||||
private static final int METHOD_ACCESS_NORMAL = 1;
|
private enum MethodAccess {NORMAL, FIELD_GET, FIELD_SET, METHOD, FUNCTION}
|
||||||
private static final int METHOD_ACCESS_FIELD_GET = 2;
|
|
||||||
private static final int METHOD_ACCESS_FIELD_SET = 3;
|
|
||||||
private static final int METHOD_ACCESS_METHOD = 4;
|
|
||||||
|
|
||||||
private boolean noSynthFlag;
|
private boolean noSynthFlag;
|
||||||
private Map<MethodWrapper, Integer> mapMethodType = new HashMap<MethodWrapper, Integer>();
|
private final Map<MethodWrapper, MethodAccess> mapMethodType = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public void propagateMemberAccess(ClassNode root) {
|
public void propagateMemberAccess(ClassNode root) {
|
||||||
@ -67,13 +47,13 @@ public class NestedMemberAccess {
|
|||||||
computeMethodTypes(nd);
|
computeMethodTypes(nd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MethodWrapper method : node.wrapper.getMethods()) {
|
for (MethodWrapper method : node.getWrapper().getMethods()) {
|
||||||
computeMethodType(node, method);
|
computeMethodType(node, method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeMethodType(ClassNode node, MethodWrapper method) {
|
private void computeMethodType(ClassNode node, MethodWrapper method) {
|
||||||
int type = METHOD_ACCESS_NORMAL;
|
MethodAccess type = MethodAccess.NORMAL;
|
||||||
|
|
||||||
if (method.root != null) {
|
if (method.root != null) {
|
||||||
DirectGraph graph = method.getOrBuildGraph();
|
DirectGraph graph = method.getOrBuildGraph();
|
||||||
@ -91,7 +71,7 @@ public class NestedMemberAccess {
|
|||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent exexpr = (ExitExprent)exprent;
|
ExitExprent exexpr = (ExitExprent)exprent;
|
||||||
if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
|
if (exexpr.getExitType() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
|
||||||
exprCore = exexpr.getValue();
|
exprCore = exexpr.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +84,7 @@ public class NestedMemberAccess {
|
|||||||
if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
|
if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
|
||||||
if (fexpr.isStatic() ||
|
if (fexpr.isStatic() ||
|
||||||
(fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) {
|
(fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) {
|
||||||
type = METHOD_ACCESS_FIELD_GET;
|
type = MethodAccess.FIELD_GET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,13 +93,23 @@ public class NestedMemberAccess {
|
|||||||
if (parcount == 1) {
|
if (parcount == 1) {
|
||||||
// this or final variable
|
// this or final variable
|
||||||
if (((VarExprent)exprCore).getIndex() != 0) {
|
if (((VarExprent)exprCore).getIndex() != 0) {
|
||||||
type = METHOD_ACCESS_FIELD_GET;
|
type = MethodAccess.FIELD_GET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Exprent.EXPRENT_FUNCTION:
|
||||||
|
// for now detect only increment/decrement
|
||||||
|
FunctionExprent functionExprent = (FunctionExprent)exprCore;
|
||||||
|
if (functionExprent.getFuncType() >= FunctionExprent.FUNCTION_IMM &&
|
||||||
|
functionExprent.getFuncType() <= FunctionExprent.FUNCTION_PPI) {
|
||||||
|
if (functionExprent.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
|
||||||
|
type = MethodAccess.FUNCTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Exprent.EXPRENT_INVOCATION:
|
case Exprent.EXPRENT_INVOCATION:
|
||||||
type = METHOD_ACCESS_METHOD;
|
type = MethodAccess.METHOD;
|
||||||
break;
|
break;
|
||||||
case Exprent.EXPRENT_ASSIGNMENT:
|
case Exprent.EXPRENT_ASSIGNMENT:
|
||||||
AssignmentExprent asexpr = (AssignmentExprent)exprCore;
|
AssignmentExprent asexpr = (AssignmentExprent)exprCore;
|
||||||
@ -131,7 +121,7 @@ public class NestedMemberAccess {
|
|||||||
if (fexpras.isStatic() ||
|
if (fexpras.isStatic() ||
|
||||||
(fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
|
(fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
|
||||||
if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
||||||
type = METHOD_ACCESS_FIELD_SET;
|
type = MethodAccess.FIELD_SET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,30 +129,31 @@ public class NestedMemberAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == MethodAccess.METHOD) { // FIXME: check for private flag of the method
|
||||||
|
|
||||||
if (type == METHOD_ACCESS_METHOD) { // FIXME: check for private flag of the method
|
type = MethodAccess.NORMAL;
|
||||||
|
|
||||||
type = METHOD_ACCESS_NORMAL;
|
|
||||||
|
|
||||||
InvocationExprent invexpr = (InvocationExprent)exprCore;
|
InvocationExprent invexpr = (InvocationExprent)exprCore;
|
||||||
|
|
||||||
if ((invexpr.isStatic() && invexpr.getLstParameters().size() == parcount) ||
|
boolean isStatic = invexpr.isStatic();
|
||||||
(!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR
|
if ((isStatic && invexpr.getLstParameters().size() == parcount) ||
|
||||||
|
(!isStatic && invexpr.getInstance().type == Exprent.EXPRENT_VAR
|
||||||
&& ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount - 1)) {
|
&& ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount - 1)) {
|
||||||
|
|
||||||
boolean equalpars = true;
|
boolean equalpars = true;
|
||||||
|
|
||||||
|
int index = isStatic ? 0 : 1;
|
||||||
for (int i = 0; i < invexpr.getLstParameters().size(); i++) {
|
for (int i = 0; i < invexpr.getLstParameters().size(); i++) {
|
||||||
Exprent parexpr = invexpr.getLstParameters().get(i);
|
Exprent parexpr = invexpr.getLstParameters().get(i);
|
||||||
if (parexpr.type != Exprent.EXPRENT_VAR ||
|
if (parexpr.type != Exprent.EXPRENT_VAR || ((VarExprent)parexpr).getIndex() != index) {
|
||||||
((VarExprent)parexpr).getIndex() != i + (invexpr.isStatic() ? 0 : 1)) {
|
|
||||||
equalpars = false;
|
equalpars = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
index += mtdesc.params[i + (isStatic ? 0 : 1)].stackSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (equalpars) {
|
if (equalpars) {
|
||||||
type = METHOD_ACCESS_METHOD;
|
type = MethodAccess.METHOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,10 +179,10 @@ public class NestedMemberAccess {
|
|||||||
if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
||||||
|
|
||||||
ExitExprent exexpr = (ExitExprent)exprentSecond;
|
ExitExprent exexpr = (ExitExprent)exprentSecond;
|
||||||
if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
|
if (exexpr.getExitType() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
|
||||||
if (exexpr.getValue().type == Exprent.EXPRENT_VAR &&
|
if (exexpr.getValue().type == Exprent.EXPRENT_VAR &&
|
||||||
((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
||||||
type = METHOD_ACCESS_FIELD_SET;
|
type = MethodAccess.FIELD_SET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +196,7 @@ public class NestedMemberAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != METHOD_ACCESS_NORMAL) {
|
if (type != MethodAccess.NORMAL) {
|
||||||
mapMethodType.put(method, type);
|
mapMethodType.put(method, type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -220,7 +211,7 @@ public class NestedMemberAccess {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MethodWrapper meth : node.wrapper.getMethods()) {
|
for (MethodWrapper meth : node.getWrapper().getMethods()) {
|
||||||
|
|
||||||
if (meth.root != null) {
|
if (meth.root != null) {
|
||||||
|
|
||||||
@ -228,8 +219,8 @@ public class NestedMemberAccess {
|
|||||||
|
|
||||||
DirectGraph graph = meth.getOrBuildGraph();
|
DirectGraph graph = meth.getOrBuildGraph();
|
||||||
|
|
||||||
HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
|
HashSet<DirectNode> setVisited = new HashSet<>();
|
||||||
LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
|
LinkedList<DirectNode> stack = new LinkedList<>();
|
||||||
stack.add(graph.first);
|
stack.add(graph.first);
|
||||||
|
|
||||||
while (!stack.isEmpty()) { // TODO: replace with interface iterator?
|
while (!stack.isEmpty()) { // TODO: replace with interface iterator?
|
||||||
@ -256,9 +247,7 @@ public class NestedMemberAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DirectNode ndx : nd.succs) {
|
stack.addAll(nd.succs);
|
||||||
stack.add(ndx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replaced) {
|
if (replaced) {
|
||||||
@ -323,12 +312,11 @@ public class NestedMemberAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
|
private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
|
||||||
|
|
||||||
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassname());
|
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassname());
|
||||||
|
|
||||||
MethodWrapper methsource = null;
|
MethodWrapper methsource = null;
|
||||||
if (node != null && node.wrapper != null) {
|
if (node != null && node.getWrapper() != null) {
|
||||||
methsource = node.wrapper.getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
|
methsource = node.getWrapper().getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methsource == null || !mapMethodType.containsKey(methsource)) {
|
if (methsource == null || !mapMethodType.containsKey(methsource)) {
|
||||||
@ -343,10 +331,10 @@ public class NestedMemberAccess {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = mapMethodType.get(methsource);
|
MethodAccess type = mapMethodType.get(methsource);
|
||||||
|
|
||||||
// // FIXME: impossible case. METHOD_ACCESS_NORMAL is not saved in the map
|
// // FIXME: impossible case. MethodAccess.NORMAL is not saved in the map
|
||||||
// if(type == METHOD_ACCESS_NORMAL) {
|
// if(type == MethodAccess.NORMAL) {
|
||||||
// return null;
|
// return null;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@ -360,11 +348,11 @@ public class NestedMemberAccess {
|
|||||||
Exprent retexprent = null;
|
Exprent retexprent = null;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case METHOD_ACCESS_FIELD_GET:
|
case FIELD_GET:
|
||||||
ExitExprent exsource = (ExitExprent)source;
|
ExitExprent exsource = (ExitExprent)source;
|
||||||
if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
|
if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
|
||||||
VarExprent var = (VarExprent)exsource.getValue();
|
VarExprent var = (VarExprent)exsource.getValue();
|
||||||
String varname = methsource.varproc.getVarName(new VarVersionPaar(var));
|
String varname = methsource.varproc.getVarName(new VarVersionPair(var));
|
||||||
|
|
||||||
if (!methdest.setOuterVarNames.contains(varname)) {
|
if (!methdest.setOuterVarNames.contains(varname)) {
|
||||||
VarNamesCollector vnc = new VarNamesCollector();
|
VarNamesCollector vnc = new VarNamesCollector();
|
||||||
@ -375,8 +363,8 @@ public class NestedMemberAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
||||||
VarExprent ret = new VarExprent(index, var.getVartype(), methdest.varproc);
|
VarExprent ret = new VarExprent(index, var.getVarType(), methdest.varproc);
|
||||||
methdest.varproc.setVarName(new VarVersionPaar(index, 0), varname);
|
methdest.varproc.setVarName(new VarVersionPair(index, 0), varname);
|
||||||
|
|
||||||
retexprent = ret;
|
retexprent = ret;
|
||||||
}
|
}
|
||||||
@ -388,7 +376,7 @@ public class NestedMemberAccess {
|
|||||||
retexprent = ret;
|
retexprent = ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case METHOD_ACCESS_FIELD_SET:
|
case FIELD_SET:
|
||||||
AssignmentExprent ret;
|
AssignmentExprent ret;
|
||||||
if (source.type == Exprent.EXPRENT_EXIT) {
|
if (source.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent extex = (ExitExprent)source;
|
ExitExprent extex = (ExitExprent)source;
|
||||||
@ -406,9 +394,17 @@ public class NestedMemberAccess {
|
|||||||
ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(1));
|
ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(1));
|
||||||
fexpr.replaceExprent(fexpr.getInstance(), invexpr.getLstParameters().get(0));
|
fexpr.replaceExprent(fexpr.getInstance(), invexpr.getLstParameters().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do not use copied bytecodes
|
||||||
|
ret.getLeft().bytecode = null;
|
||||||
|
ret.getRight().bytecode = null;
|
||||||
|
|
||||||
retexprent = ret;
|
retexprent = ret;
|
||||||
break;
|
break;
|
||||||
case METHOD_ACCESS_METHOD:
|
case FUNCTION:
|
||||||
|
retexprent = replaceFunction(invexpr, source);
|
||||||
|
break;
|
||||||
|
case METHOD:
|
||||||
if (source.type == Exprent.EXPRENT_EXIT) {
|
if (source.type == Exprent.EXPRENT_EXIT) {
|
||||||
source = ((ExitExprent)source).getValue();
|
source = ((ExitExprent)source).getValue();
|
||||||
}
|
}
|
||||||
@ -430,6 +426,10 @@ public class NestedMemberAccess {
|
|||||||
|
|
||||||
|
|
||||||
if (retexprent != null) {
|
if (retexprent != null) {
|
||||||
|
// preserve original bytecodes
|
||||||
|
retexprent.bytecode = null;
|
||||||
|
retexprent.addBytecodeOffsets(invexpr.bytecode);
|
||||||
|
|
||||||
// hide synthetic access method
|
// hide synthetic access method
|
||||||
boolean hide = true;
|
boolean hide = true;
|
||||||
|
|
||||||
@ -440,10 +440,31 @@ public class NestedMemberAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hide) {
|
if (hide) {
|
||||||
node.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
|
node.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retexprent;
|
return retexprent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Exprent replaceFunction(final InvocationExprent invexpr, final Exprent source) {
|
||||||
|
FunctionExprent functionExprent = (FunctionExprent)((ExitExprent)source).getValue().copy();
|
||||||
|
|
||||||
|
List<Exprent> lstParameters = invexpr.getLstParameters();
|
||||||
|
|
||||||
|
FieldExprent fieldExprent = (FieldExprent)functionExprent.getLstOperands().get(0);
|
||||||
|
if (fieldExprent.isStatic()) {
|
||||||
|
if (!lstParameters.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return functionExprent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstParameters.size() != 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldExprent.replaceExprent(fieldExprent.getInstance(), lstParameters.get(0));
|
||||||
|
return functionExprent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.code;
|
package org.jetbrains.java.decompiler.modules.code;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
import org.jetbrains.java.decompiler.code.Instruction;
|
import org.jetbrains.java.decompiler.code.Instruction;
|
||||||
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
||||||
|
import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
||||||
@ -26,12 +13,12 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class DeadCodeHelper {
|
public final class DeadCodeHelper {
|
||||||
|
|
||||||
public static void removeDeadBlocks(ControlFlowGraph graph) {
|
public static void removeDeadBlocks(ControlFlowGraph graph) {
|
||||||
|
|
||||||
LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
|
LinkedList<BasicBlock> stack = new LinkedList<>();
|
||||||
HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> setStacked = new HashSet<>();
|
||||||
|
|
||||||
stack.add(graph.getFirst());
|
stack.add(graph.getFirst());
|
||||||
setStacked.add(graph.getFirst());
|
setStacked.add(graph.getFirst());
|
||||||
@ -39,7 +26,7 @@ public class DeadCodeHelper {
|
|||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
BasicBlock block = stack.removeFirst();
|
BasicBlock block = stack.removeFirst();
|
||||||
|
|
||||||
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
|
List<BasicBlock> lstSuccs = new ArrayList<>(block.getSuccs());
|
||||||
lstSuccs.addAll(block.getSuccExceptions());
|
lstSuccs.addAll(block.getSuccExceptions());
|
||||||
|
|
||||||
for (BasicBlock succ : lstSuccs) {
|
for (BasicBlock succ : lstSuccs) {
|
||||||
@ -50,7 +37,7 @@ public class DeadCodeHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<BasicBlock> setAllBlocks = new HashSet<BasicBlock>(graph.getBlocks());
|
HashSet<BasicBlock> setAllBlocks = new HashSet<>(graph.getBlocks());
|
||||||
setAllBlocks.removeAll(setStacked);
|
setAllBlocks.removeAll(setStacked);
|
||||||
|
|
||||||
for (BasicBlock block : setAllBlocks) {
|
for (BasicBlock block : setAllBlocks) {
|
||||||
@ -94,7 +81,7 @@ public class DeadCodeHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<BasicBlock> setExits = new HashSet<BasicBlock>(graph.getLast().getPreds());
|
HashSet<BasicBlock> setExits = new HashSet<>(graph.getLast().getPreds());
|
||||||
|
|
||||||
if (block.getPredExceptions().isEmpty() &&
|
if (block.getPredExceptions().isEmpty() &&
|
||||||
(!setExits.contains(block) || block.getPreds().size() == 1)) {
|
(!setExits.contains(block) || block.getPreds().size() == 1)) {
|
||||||
@ -109,15 +96,15 @@ public class DeadCodeHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds());
|
HashSet<BasicBlock> setPreds = new HashSet<>(block.getPreds());
|
||||||
HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs());
|
HashSet<BasicBlock> setSuccs = new HashSet<>(block.getSuccs());
|
||||||
|
|
||||||
// collect common exception ranges of predecessors and successors
|
// collect common exception ranges of predecessors and successors
|
||||||
HashSet<BasicBlock> setCommonExceptionHandlers = null;
|
HashSet<BasicBlock> setCommonExceptionHandlers = null;
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
for (BasicBlock pred : i == 0 ? setPreds : setSuccs) {
|
for (BasicBlock pred : i == 0 ? setPreds : setSuccs) {
|
||||||
if (setCommonExceptionHandlers == null) {
|
if (setCommonExceptionHandlers == null) {
|
||||||
setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions());
|
setCommonExceptionHandlers = new HashSet<>(pred.getSuccExceptions());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
|
setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
|
||||||
@ -159,7 +146,7 @@ public class DeadCodeHelper {
|
|||||||
BasicBlock pred = block.getPreds().get(0);
|
BasicBlock pred = block.getPreds().get(0);
|
||||||
pred.removeSuccessor(block);
|
pred.removeSuccessor(block);
|
||||||
|
|
||||||
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
|
List<BasicBlock> lstSuccs = new ArrayList<>(block.getSuccs());
|
||||||
for (BasicBlock succ : lstSuccs) {
|
for (BasicBlock succ : lstSuccs) {
|
||||||
block.removeSuccessor(succ);
|
block.removeSuccessor(succ);
|
||||||
pred.addSuccessor(succ);
|
pred.addSuccessor(succ);
|
||||||
@ -205,13 +192,13 @@ public class DeadCodeHelper {
|
|||||||
|
|
||||||
public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) {
|
public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) {
|
||||||
|
|
||||||
HashSet<BasicBlock> marked = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> marked = new HashSet<>();
|
||||||
|
|
||||||
if (block == dom) {
|
if (block == dom) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
|
LinkedList<BasicBlock> lstNodes = new LinkedList<>();
|
||||||
lstNodes.add(block);
|
lstNodes.add(block);
|
||||||
|
|
||||||
while (!lstNodes.isEmpty()) {
|
while (!lstNodes.isEmpty()) {
|
||||||
@ -230,14 +217,14 @@ public class DeadCodeHelper {
|
|||||||
|
|
||||||
for (int i = 0; i < node.getPreds().size(); i++) {
|
for (int i = 0; i < node.getPreds().size(); i++) {
|
||||||
BasicBlock pred = node.getPreds().get(i);
|
BasicBlock pred = node.getPreds().get(i);
|
||||||
if (!marked.contains(pred) && pred != dom) {
|
if (pred != dom && !marked.contains(pred)) {
|
||||||
lstNodes.add(pred);
|
lstNodes.add(pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < node.getPredExceptions().size(); i++) {
|
for (int i = 0; i < node.getPredExceptions().size(); i++) {
|
||||||
BasicBlock pred = node.getPredExceptions().get(i);
|
BasicBlock pred = node.getPredExceptions().get(i);
|
||||||
if (!marked.contains(pred) && pred != dom) {
|
if (pred != dom && !marked.contains(pred)) {
|
||||||
lstNodes.add(pred);
|
lstNodes.add(pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,7 +239,7 @@ public class DeadCodeHelper {
|
|||||||
Instruction instr = block.getLastInstruction();
|
Instruction instr = block.getLastInstruction();
|
||||||
|
|
||||||
if (instr != null && instr.opcode == CodeConstants.opc_goto) {
|
if (instr != null && instr.opcode == CodeConstants.opc_goto) {
|
||||||
block.getSeq().removeInstruction(block.getSeq().length() - 1);
|
block.getSeq().removeLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,12 +249,161 @@ public class DeadCodeHelper {
|
|||||||
public static void connectDummyExitBlock(ControlFlowGraph graph) {
|
public static void connectDummyExitBlock(ControlFlowGraph graph) {
|
||||||
|
|
||||||
BasicBlock exit = graph.getLast();
|
BasicBlock exit = graph.getLast();
|
||||||
for (BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) {
|
for (BasicBlock block : new HashSet<>(exit.getPreds())) {
|
||||||
exit.removePredecessor(block);
|
exit.removePredecessor(block);
|
||||||
block.addSuccessor(exit);
|
block.addSuccessor(exit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void extendSynchronizedRangeToMonitorexit(ControlFlowGraph graph) {
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
|
||||||
|
boolean range_extended = false;
|
||||||
|
|
||||||
|
for (ExceptionRangeCFG range : graph.getExceptions()) {
|
||||||
|
|
||||||
|
Set<BasicBlock> setPreds = new HashSet<>();
|
||||||
|
for (BasicBlock block : range.getProtectedRange()) {
|
||||||
|
setPreds.addAll(block.getPreds());
|
||||||
|
}
|
||||||
|
for (BasicBlock basicBlock : range.getProtectedRange()) {
|
||||||
|
setPreds.remove(basicBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(setPreds.size() != 1) {
|
||||||
|
continue; // multiple predecessors, obfuscated range
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock predBlock = setPreds.iterator().next();
|
||||||
|
InstructionSequence predSeq = predBlock.getSeq();
|
||||||
|
if(predSeq.isEmpty() || predSeq.getLastInstr().opcode != CodeConstants.opc_monitorenter) {
|
||||||
|
continue; // not a synchronized range
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean monitorexit_in_range = false;
|
||||||
|
Set<BasicBlock> setProtectedBlocks = new HashSet<>(range.getProtectedRange());
|
||||||
|
setProtectedBlocks.add(range.getHandler());
|
||||||
|
|
||||||
|
for (BasicBlock block : setProtectedBlocks) {
|
||||||
|
InstructionSequence blockSeq = block.getSeq();
|
||||||
|
for (int i = 0; i < blockSeq.length(); i++) {
|
||||||
|
if (blockSeq.getInstr(i).opcode == CodeConstants.opc_monitorexit) {
|
||||||
|
monitorexit_in_range = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(monitorexit_in_range) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(monitorexit_in_range) {
|
||||||
|
continue; // protected range already contains monitorexit
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<BasicBlock> setSuccs = new HashSet<>();
|
||||||
|
for (BasicBlock block : range.getProtectedRange()) {
|
||||||
|
setSuccs.addAll(block.getSuccs());
|
||||||
|
}
|
||||||
|
for (BasicBlock basicBlock : range.getProtectedRange()) {
|
||||||
|
setSuccs.remove(basicBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(setSuccs.size() != 1) {
|
||||||
|
continue; // non-unique successor
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock succBlock = setSuccs.iterator().next();
|
||||||
|
InstructionSequence succSeq = succBlock.getSeq();
|
||||||
|
|
||||||
|
int succ_monitorexit_index = -1;
|
||||||
|
for (int i = 0; i < succSeq.length(); i++) {
|
||||||
|
if (succSeq.getInstr(i).opcode == CodeConstants.opc_monitorexit) {
|
||||||
|
succ_monitorexit_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(succ_monitorexit_index < 0) {
|
||||||
|
continue; // monitorexit not found in the single successor block
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock handlerBlock = range.getHandler();
|
||||||
|
if(handlerBlock.getSuccs().size() != 1) {
|
||||||
|
continue; // non-unique handler successor
|
||||||
|
}
|
||||||
|
BasicBlock succHandler = handlerBlock.getSuccs().get(0);
|
||||||
|
InstructionSequence succHandlerSeq = succHandler.getSeq();
|
||||||
|
if(succHandlerSeq.isEmpty() || succHandlerSeq.getLastInstr().opcode != CodeConstants.opc_athrow) {
|
||||||
|
continue; // not a standard synchronized range
|
||||||
|
}
|
||||||
|
|
||||||
|
int handler_monitorexit_index = -1;
|
||||||
|
for (int i = 0; i < succHandlerSeq.length(); i++) {
|
||||||
|
if (succHandlerSeq.getInstr(i).opcode == CodeConstants.opc_monitorexit) {
|
||||||
|
handler_monitorexit_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(handler_monitorexit_index < 0) {
|
||||||
|
continue; // monitorexit not found in the handler successor block
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks successful, prerequisites satisfied, now extend the range
|
||||||
|
if(succ_monitorexit_index < succSeq.length() - 1) { // split block
|
||||||
|
|
||||||
|
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||||
|
for(int counter = 0; counter < succ_monitorexit_index; counter++) {
|
||||||
|
seq.addInstruction(succSeq.getInstr(0), -1);
|
||||||
|
succSeq.removeInstruction(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a separate block
|
||||||
|
BasicBlock newblock = new BasicBlock(++graph.last_id);
|
||||||
|
newblock.setSeq(seq);
|
||||||
|
|
||||||
|
// insert new block
|
||||||
|
for (BasicBlock block : succBlock.getPreds()) {
|
||||||
|
block.replaceSuccessor(succBlock, newblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
newblock.addSuccessor(succBlock);
|
||||||
|
graph.getBlocks().addWithKey(newblock, newblock.id);
|
||||||
|
|
||||||
|
succBlock = newblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy exception edges and extend protected ranges (successor block)
|
||||||
|
BasicBlock rangeExitBlock = succBlock.getPreds().get(0);
|
||||||
|
for (int j = 0; j < rangeExitBlock.getSuccExceptions().size(); j++) {
|
||||||
|
BasicBlock hd = rangeExitBlock.getSuccExceptions().get(j);
|
||||||
|
succBlock.addSuccessorException(hd);
|
||||||
|
|
||||||
|
ExceptionRangeCFG rng = graph.getExceptionRange(hd, rangeExitBlock);
|
||||||
|
rng.getProtectedRange().add(succBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy instructions (handler successor block)
|
||||||
|
InstructionSequence handlerSeq = handlerBlock.getSeq();
|
||||||
|
for(int counter = 0; counter < handler_monitorexit_index; counter++) {
|
||||||
|
handlerSeq.addInstruction(succHandlerSeq.getInstr(0), -1);
|
||||||
|
succHandlerSeq.removeInstruction(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
range_extended = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!range_extended) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void incorporateValueReturns(ControlFlowGraph graph) {
|
public static void incorporateValueReturns(ControlFlowGraph graph) {
|
||||||
|
|
||||||
for (BasicBlock block : graph.getBlocks()) {
|
for (BasicBlock block : graph.getBlocks()) {
|
||||||
@ -311,8 +447,8 @@ public class DeadCodeHelper {
|
|||||||
|
|
||||||
if (!block.getPreds().isEmpty()) {
|
if (!block.getPreds().isEmpty()) {
|
||||||
|
|
||||||
HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> setPredHandlersUnion = new HashSet<>();
|
||||||
HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<>();
|
||||||
|
|
||||||
boolean firstpred = true;
|
boolean firstpred = true;
|
||||||
for (BasicBlock pred : block.getPreds()) {
|
for (BasicBlock pred : block.getPreds()) {
|
||||||
@ -328,7 +464,9 @@ public class DeadCodeHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add exception ranges from predecessors
|
// add exception ranges from predecessors
|
||||||
setPredHandlersIntersection.removeAll(block.getSuccExceptions());
|
for (BasicBlock basicBlock : block.getSuccExceptions()) {
|
||||||
|
setPredHandlersIntersection.remove(basicBlock);
|
||||||
|
}
|
||||||
BasicBlock predecessor = block.getPreds().get(0);
|
BasicBlock predecessor = block.getPreds().get(0);
|
||||||
|
|
||||||
for (BasicBlock handler : setPredHandlersIntersection) {
|
for (BasicBlock handler : setPredHandlersIntersection) {
|
||||||
@ -339,7 +477,7 @@ public class DeadCodeHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove redundant ranges
|
// remove redundant ranges
|
||||||
HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions());
|
HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<>(block.getSuccExceptions());
|
||||||
setRangesToBeRemoved.removeAll(setPredHandlersUnion);
|
setRangesToBeRemoved.removeAll(setPredHandlersUnion);
|
||||||
|
|
||||||
for (BasicBlock handler : setRangesToBeRemoved) {
|
for (BasicBlock handler : setRangesToBeRemoved) {
|
||||||
@ -369,7 +507,7 @@ public class DeadCodeHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove superfluous ranges from successors
|
// remove superfluous ranges from successors
|
||||||
for (BasicBlock succ : new HashSet<BasicBlock>(block.getSuccExceptions())) {
|
for (BasicBlock succ : new HashSet<>(block.getSuccExceptions())) {
|
||||||
if (!bpred.getSuccExceptions().contains(succ)) {
|
if (!bpred.getSuccExceptions().contains(succ)) {
|
||||||
ExceptionRangeCFG range = graph.getExceptionRange(succ, block);
|
ExceptionRangeCFG range = graph.getExceptionRange(succ, block);
|
||||||
|
|
||||||
@ -416,6 +554,7 @@ public class DeadCodeHelper {
|
|||||||
|
|
||||||
if (sameRanges) {
|
if (sameRanges) {
|
||||||
seq.addSequence(next.getSeq());
|
seq.addSequence(next.getSeq());
|
||||||
|
block.getInstrOldOffsets().addAll(next.getInstrOldOffsets());
|
||||||
next.getSeq().clear();
|
next.getSeq().clear();
|
||||||
|
|
||||||
removeEmptyBlock(graph, next, true);
|
removeEmptyBlock(graph, next, true);
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class ClasspathHelper {
|
||||||
|
|
||||||
|
private static final Map<String, Method> METHOD_CACHE = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
public static Method findMethod(String classname, String methodName, MethodDescriptor descriptor) {
|
||||||
|
String targetClass = classname.replace('/', '.');
|
||||||
|
String methodSignature = buildMethodSignature(targetClass + '.' + methodName, descriptor);
|
||||||
|
|
||||||
|
Method method;
|
||||||
|
if (METHOD_CACHE.containsKey(methodSignature)) {
|
||||||
|
method = METHOD_CACHE.get(methodSignature);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
method = findMethodOnClasspath(targetClass, methodSignature);
|
||||||
|
METHOD_CACHE.put(methodSignature, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Method findMethodOnClasspath(String targetClass, String methodSignature) {
|
||||||
|
try {
|
||||||
|
// use bootstrap classloader to only provide access to JRE classes
|
||||||
|
Class cls = new ClassLoader(null) {}.loadClass(targetClass);
|
||||||
|
for (Method mtd : cls.getMethods()) {
|
||||||
|
// use contains() to ignore access modifiers and thrown exceptions
|
||||||
|
if (mtd.toString().contains(methodSignature)) {
|
||||||
|
return mtd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildMethodSignature(String name, MethodDescriptor md) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
appendType(sb, md.ret);
|
||||||
|
sb.append(' ').append(name).append('(');
|
||||||
|
for (VarType param : md.params) {
|
||||||
|
appendType(sb, param);
|
||||||
|
sb.append(',');
|
||||||
|
}
|
||||||
|
if (sb.charAt(sb.length() - 1) == ',') {
|
||||||
|
sb.setLength(sb.length() - 1);
|
||||||
|
}
|
||||||
|
sb.append(')');
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendType(StringBuilder sb, VarType type) {
|
||||||
|
sb.append(type.value.replace('/', '.'));
|
||||||
|
for (int i = 0; i < type.arrayDim; i++) {
|
||||||
|
sb.append("[]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
||||||
@ -21,11 +7,11 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
|
||||||
public class ClearStructHelper {
|
public final class ClearStructHelper {
|
||||||
|
|
||||||
public static void clearStatements(RootStatement root) {
|
public static void clearStatements(RootStatement root) {
|
||||||
|
|
||||||
LinkedList<Statement> stack = new LinkedList<Statement>();
|
LinkedList<Statement> stack = new LinkedList<>();
|
||||||
stack.add(root);
|
stack.add(root);
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
|
@ -1,29 +1,19 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
||||||
|
import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
|
||||||
|
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class ConcatenationHelper {
|
public final class ConcatenationHelper {
|
||||||
|
|
||||||
private static final String builderClass = "java/lang/StringBuilder";
|
private static final String builderClass = "java/lang/StringBuilder";
|
||||||
private static final String bufferClass = "java/lang/StringBuffer";
|
private static final String bufferClass = "java/lang/StringBuffer";
|
||||||
@ -52,6 +42,12 @@ public class ConcatenationHelper {
|
|||||||
exprTmp = iex.getInstance();
|
exprTmp = iex.getInstance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ("makeConcatWithConstants".equals(iex.getName())) { // java 9 style
|
||||||
|
List<Exprent> parameters = extractParameters(iex.getBootstrapArguments(), iex);
|
||||||
|
if (parameters.size() >= 2) {
|
||||||
|
return createConcatExprent(parameters, expr.bytecode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exprTmp == null) {
|
if (exprTmp == null) {
|
||||||
@ -60,7 +56,7 @@ public class ConcatenationHelper {
|
|||||||
|
|
||||||
|
|
||||||
// iterate in depth, collecting possible operands
|
// iterate in depth, collecting possible operands
|
||||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
List<Exprent> lstOperands = new ArrayList<>();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
@ -104,7 +100,7 @@ public class ConcatenationHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (first2str == 0) {
|
if (first2str == 0) {
|
||||||
lstOperands.add(0, new ConstExprent(VarType.VARTYPE_STRING, ""));
|
lstOperands.add(0, new ConstExprent(VarType.VARTYPE_STRING, "", expr.bytecode));
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove redundant String.valueOf
|
// remove redundant String.valueOf
|
||||||
@ -125,20 +121,69 @@ public class ConcatenationHelper {
|
|||||||
lstOperands.set(i, rep);
|
lstOperands.set(i, rep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return createConcatExprent(lstOperands, expr.bytecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Exprent createConcatExprent(List<Exprent> lstOperands, Set<Integer> bytecode) {
|
||||||
// build exprent to return
|
// build exprent to return
|
||||||
Exprent func = lstOperands.get(0);
|
Exprent func = lstOperands.get(0);
|
||||||
|
|
||||||
for (int i = 1; i < lstOperands.size(); i++) {
|
for (int i = 1; i < lstOperands.size(); i++) {
|
||||||
List<Exprent> lstTmp = new ArrayList<Exprent>();
|
func = new FunctionExprent(FunctionExprent.FUNCTION_STR_CONCAT, Arrays.asList(func, lstOperands.get(i)), bytecode);
|
||||||
lstTmp.add(func);
|
|
||||||
lstTmp.add(lstOperands.get(i));
|
|
||||||
func = new FunctionExprent(FunctionExprent.FUNCTION_STRCONCAT, lstTmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See StringConcatFactory in jdk sources
|
||||||
|
private static final char TAG_ARG = '\u0001';
|
||||||
|
private static final char TAG_CONST = '\u0002';
|
||||||
|
|
||||||
|
private static List<Exprent> extractParameters(List<PooledConstant> bootstrapArguments, InvocationExprent expr) {
|
||||||
|
List<Exprent> parameters = expr.getLstParameters();
|
||||||
|
if (bootstrapArguments != null) {
|
||||||
|
PooledConstant constant = bootstrapArguments.get(0);
|
||||||
|
if (constant.type == CodeConstants.CONSTANT_String) {
|
||||||
|
String recipe = ((PrimitiveConstant)constant).getString();
|
||||||
|
|
||||||
|
List<Exprent> res = new ArrayList<>();
|
||||||
|
StringBuilder acc = new StringBuilder();
|
||||||
|
int parameterId = 0;
|
||||||
|
for (int i = 0; i < recipe.length(); i++) {
|
||||||
|
char c = recipe.charAt(i);
|
||||||
|
|
||||||
|
if (c == TAG_CONST || c == TAG_ARG) {
|
||||||
|
// Detected a special tag, flush all accumulated characters
|
||||||
|
// as a constant first:
|
||||||
|
if (acc.length() > 0) {
|
||||||
|
res.add(new ConstExprent(VarType.VARTYPE_STRING, acc.toString(), expr.bytecode));
|
||||||
|
acc.setLength(0);
|
||||||
|
}
|
||||||
|
if (c == TAG_CONST) {
|
||||||
|
// skip for now
|
||||||
|
}
|
||||||
|
if (c == TAG_ARG) {
|
||||||
|
res.add(parameters.get(parameterId++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Not a special characters, this is a constant embedded into
|
||||||
|
// the recipe itself.
|
||||||
|
acc.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the remaining characters as constant:
|
||||||
|
if (acc.length() > 0) {
|
||||||
|
res.add(new ConstExprent(VarType.VARTYPE_STRING, acc.toString(), expr.bytecode));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ArrayList<>(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isAppendConcat(InvocationExprent expr, VarType cltype) {
|
private static boolean isAppendConcat(InvocationExprent expr, VarType cltype) {
|
||||||
|
|
||||||
if ("append".equals(expr.getName())) {
|
if ("append".equals(expr.getName())) {
|
||||||
@ -167,13 +212,9 @@ public class ConcatenationHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNewConcat(NewExprent expr, VarType cltype) {
|
private static boolean isNewConcat(NewExprent expr, VarType cltype) {
|
||||||
|
if (expr.getNewType().equals(cltype)) {
|
||||||
if (expr.getNewtype().equals(cltype)) {
|
|
||||||
VarType[] params = expr.getConstructor().getDescriptor().params;
|
VarType[] params = expr.getConstructor().getDescriptor().params;
|
||||||
if (params.length == 0 || (params.length == 1 &&
|
return params.length == 0 || params.length == 1 && params[0].equals(VarType.VARTYPE_STRING);
|
||||||
params[0].equals(VarType.VARTYPE_STRING))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,33 +1,22 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
public class DecHelper {
|
public final class DecHelper {
|
||||||
|
|
||||||
public static boolean checkStatementExceptions(List<Statement> lst) {
|
public static boolean checkStatementExceptions(List<? extends Statement> lst) {
|
||||||
|
|
||||||
Set<Statement> all = new HashSet<Statement>(lst);
|
Set<Statement> all = new HashSet<>(lst);
|
||||||
|
|
||||||
Set<Statement> handlers = new HashSet<Statement>();
|
Set<Statement> handlers = new HashSet<>();
|
||||||
Set<Statement> intersection = null;
|
Set<Statement> intersection = null;
|
||||||
|
|
||||||
for (Statement stat : lst) {
|
for (Statement stat : lst) {
|
||||||
@ -37,7 +26,7 @@ public class DecHelper {
|
|||||||
intersection = setNew;
|
intersection = setNew;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
HashSet<Statement> interclone = new HashSet<Statement>(intersection);
|
HashSet<Statement> interclone = new HashSet<>(intersection);
|
||||||
interclone.removeAll(setNew);
|
interclone.removeAll(setNew);
|
||||||
|
|
||||||
intersection.retainAll(setNew);
|
intersection.retainAll(setNew);
|
||||||
@ -66,7 +55,7 @@ public class DecHelper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isChoiceStatement(Statement head, List<Statement> lst) {
|
public static boolean isChoiceStatement(Statement head, List<? super Statement> lst) {
|
||||||
|
|
||||||
Statement post = null;
|
Statement post = null;
|
||||||
|
|
||||||
@ -159,7 +148,7 @@ public class DecHelper {
|
|||||||
if (head == statd) {
|
if (head == statd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!setDest.contains(statd) && post != statd) {
|
if (post != statd && !setDest.contains(statd)) {
|
||||||
if (post != null) {
|
if (post != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -194,25 +183,17 @@ public class DecHelper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<Statement> getUniquePredExceptions(Statement head) {
|
||||||
public static HashSet<Statement> getUniquePredExceptions(Statement head) {
|
Set<Statement> setHandlers = new HashSet<>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
|
||||||
|
setHandlers.removeIf(statement -> statement.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).size() > 1);
|
||||||
HashSet<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
|
|
||||||
|
|
||||||
Iterator<Statement> it = setHandlers.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
if (it.next().getPredecessorEdges(StatEdge.TYPE_EXCEPTION).size() > 1) {
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return setHandlers;
|
return setHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Exprent> copyExprentList(List<Exprent> lst) {
|
public static List<Exprent> copyExprentList(List<? extends Exprent> lst) {
|
||||||
List<Exprent> ret = new ArrayList<Exprent>();
|
List<Exprent> ret = new ArrayList<>();
|
||||||
for (Exprent expr : lst) {
|
for (Exprent expr : lst) {
|
||||||
ret.add(expr.copy());
|
ret.add(expr.copy());
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
||||||
@ -30,12 +16,12 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class DomHelper {
|
public final class DomHelper {
|
||||||
|
|
||||||
|
|
||||||
private static RootStatement graphToStatement(ControlFlowGraph graph) {
|
private static RootStatement graphToStatement(ControlFlowGraph graph) {
|
||||||
|
|
||||||
VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
|
VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<>();
|
||||||
VBStyleCollection<BasicBlock, Integer> blocks = graph.getBlocks();
|
VBStyleCollection<BasicBlock, Integer> blocks = graph.getBlocks();
|
||||||
|
|
||||||
for (BasicBlock block : blocks) {
|
for (BasicBlock block : blocks) {
|
||||||
@ -46,8 +32,7 @@ public class DomHelper {
|
|||||||
// head statement
|
// head statement
|
||||||
Statement firstst = stats.getWithKey(firstblock.id);
|
Statement firstst = stats.getWithKey(firstblock.id);
|
||||||
// dummy exit statement
|
// dummy exit statement
|
||||||
Statement dummyexit = new Statement();
|
DummyExitStatement dummyexit = new DummyExitStatement();
|
||||||
dummyexit.type = Statement.TYPE_DUMMYEXIT;
|
|
||||||
|
|
||||||
Statement general;
|
Statement general;
|
||||||
if (stats.size() > 1 || firstblock.isSuccessor(firstblock)) { // multiple basic blocks or an infinite loop of one block
|
if (stats.size() > 1 || firstblock.isSuccessor(firstblock)) { // multiple basic blocks or an infinite loop of one block
|
||||||
@ -104,14 +89,14 @@ public class DomHelper {
|
|||||||
|
|
||||||
public static VBStyleCollection<List<Integer>, Integer> calcPostDominators(Statement container) {
|
public static VBStyleCollection<List<Integer>, Integer> calcPostDominators(Statement container) {
|
||||||
|
|
||||||
HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<Statement, FastFixedSet<Statement>>();
|
HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<>();
|
||||||
|
|
||||||
StrongConnectivityHelper schelper = new StrongConnectivityHelper(container);
|
StrongConnectivityHelper schelper = new StrongConnectivityHelper(container);
|
||||||
List<List<Statement>> components = schelper.getComponents();
|
List<List<Statement>> components = schelper.getComponents();
|
||||||
|
|
||||||
List<Statement> lstStats = container.getPostReversePostOrderList(StrongConnectivityHelper.getExitReps(components));
|
List<Statement> lstStats = container.getPostReversePostOrderList(StrongConnectivityHelper.getExitReps(components));
|
||||||
|
|
||||||
FastFixedSetFactory<Statement> factory = new FastFixedSetFactory<Statement>(lstStats);
|
FastFixedSetFactory<Statement> factory = new FastFixedSetFactory<>(lstStats);
|
||||||
|
|
||||||
FastFixedSet<Statement> setFlagNodes = factory.spawnEmptySet();
|
FastFixedSet<Statement> setFlagNodes = factory.spawnEmptySet();
|
||||||
setFlagNodes.setAllElements();
|
setFlagNodes.setAllElements();
|
||||||
@ -177,26 +162,22 @@ public class DomHelper {
|
|||||||
}
|
}
|
||||||
while (!setFlagNodes.isEmpty());
|
while (!setFlagNodes.isEmpty());
|
||||||
|
|
||||||
VBStyleCollection<List<Integer>, Integer> ret = new VBStyleCollection<List<Integer>, Integer>();
|
VBStyleCollection<List<Integer>, Integer> ret = new VBStyleCollection<>();
|
||||||
List<Statement> lstRevPost = container.getReversePostOrderList(); // sort order crucial!
|
List<Statement> lstRevPost = container.getReversePostOrderList(); // sort order crucial!
|
||||||
|
|
||||||
final HashMap<Integer, Integer> mapSortOrder = new HashMap<Integer, Integer>();
|
final HashMap<Integer, Integer> mapSortOrder = new HashMap<>();
|
||||||
for (int i = 0; i < lstRevPost.size(); i++) {
|
for (int i = 0; i < lstRevPost.size(); i++) {
|
||||||
mapSortOrder.put(lstRevPost.get(i).id, i);
|
mapSortOrder.put(lstRevPost.get(i).id, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Statement st : lstStats) {
|
for (Statement st : lstStats) {
|
||||||
|
|
||||||
List<Integer> lstPosts = new ArrayList<Integer>();
|
List<Integer> lstPosts = new ArrayList<>();
|
||||||
for (Statement stt : lists.get(st)) {
|
for (Statement stt : lists.get(st)) {
|
||||||
lstPosts.add(stt.id);
|
lstPosts.add(stt.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(lstPosts, new Comparator<Integer>() {
|
lstPosts.sort(Comparator.comparing(mapSortOrder::get));
|
||||||
public int compare(Integer o1, Integer o2) {
|
|
||||||
return mapSortOrder.get(o1).compareTo(mapSortOrder.get(o2));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (lstPosts.size() > 1 && lstPosts.get(0).intValue() == st.id) {
|
if (lstPosts.size() > 1 && lstPosts.get(0).intValue() == st.id) {
|
||||||
lstPosts.add(lstPosts.remove(0));
|
lstPosts.add(lstPosts.remove(0));
|
||||||
@ -212,11 +193,17 @@ public class DomHelper {
|
|||||||
|
|
||||||
RootStatement root = graphToStatement(graph);
|
RootStatement root = graphToStatement(graph);
|
||||||
|
|
||||||
if (!processStatement(root, new HashMap<Integer, Set<Integer>>())) {
|
if (!processStatement(root, new HashMap<>())) {
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// DotExporter.toDotFile(root.getFirst().getStats().get(13), new File("c:\\Temp\\stat1.dot"));
|
||||||
|
// } catch (Exception ex) {
|
||||||
|
// ex.printStackTrace();
|
||||||
|
// }
|
||||||
throw new RuntimeException("parsing failure!");
|
throw new RuntimeException("parsing failure!");
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
LabelHelper.lowContinueLabels(root, new HashSet<>());
|
||||||
|
|
||||||
SequenceHelper.condenseSequences(root);
|
SequenceHelper.condenseSequences(root);
|
||||||
root.buildMonitorFlags();
|
root.buildMonitorFlags();
|
||||||
@ -286,7 +273,7 @@ public class DomHelper {
|
|||||||
SynchronizedStatement sync = new SynchronizedStatement(current, ca.getFirst(), ca.getHandler());
|
SynchronizedStatement sync = new SynchronizedStatement(current, ca.getFirst(), ca.getHandler());
|
||||||
sync.setAllParent();
|
sync.setAllParent();
|
||||||
|
|
||||||
for (StatEdge edge : new HashSet<StatEdge>(ca.getLabelEdges())) {
|
for (StatEdge edge : new HashSet<>(ca.getLabelEdges())) {
|
||||||
sync.addLabeledEdge(edge);
|
sync.addLabeledEdge(edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +343,7 @@ public class DomHelper {
|
|||||||
// DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
|
// DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
|
||||||
// } catch(Exception ex) {ex.printStackTrace();}
|
// } catch(Exception ex) {ex.printStackTrace();}
|
||||||
|
|
||||||
mapExtPost = new HashMap<Integer, Set<Integer>>();
|
mapExtPost = new HashMap<>();
|
||||||
mapRefreshed = true;
|
mapRefreshed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +364,7 @@ public class DomHelper {
|
|||||||
Statement stat = findGeneralStatement(general, forceall, mapExtPost);
|
Statement stat = findGeneralStatement(general, forceall, mapExtPost);
|
||||||
|
|
||||||
if (stat != null) {
|
if (stat != null) {
|
||||||
boolean complete = processStatement(stat, general.getFirst() == stat ? mapExtPost : new HashMap<Integer, Set<Integer>>());
|
boolean complete = processStatement(stat, general.getFirst() == stat ? mapExtPost : new HashMap<>());
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
// replace general purpose statement with simple one
|
// replace general purpose statement with simple one
|
||||||
@ -387,7 +374,7 @@ public class DomHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapExtPost = new HashMap<Integer, Set<Integer>>();
|
mapExtPost = new HashMap<>();
|
||||||
mapRefreshed = true;
|
mapRefreshed = true;
|
||||||
reducibility = 0;
|
reducibility = 0;
|
||||||
}
|
}
|
||||||
@ -408,7 +395,7 @@ public class DomHelper {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mapExtPost = new HashMap<Integer, Set<Integer>>();
|
mapExtPost = new HashMap<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,13 +413,13 @@ public class DomHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (forceall) {
|
if (forceall) {
|
||||||
vbPost = new VBStyleCollection<List<Integer>, Integer>();
|
vbPost = new VBStyleCollection<>();
|
||||||
List<Statement> lstAll = stat.getPostReversePostOrderList();
|
List<Statement> lstAll = stat.getPostReversePostOrderList();
|
||||||
|
|
||||||
for (Statement st : lstAll) {
|
for (Statement st : lstAll) {
|
||||||
Set<Integer> set = mapExtPost.get(st.id);
|
Set<Integer> set = mapExtPost.get(st.id);
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
vbPost.addWithKey(new ArrayList<Integer>(set), st.id); // FIXME: sort order!!
|
vbPost.addWithKey(new ArrayList<>(set), st.id); // FIXME: sort order!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +429,7 @@ public class DomHelper {
|
|||||||
for (Integer id : setFirst) {
|
for (Integer id : setFirst) {
|
||||||
List<Integer> lst = vbPost.getWithKey(id);
|
List<Integer> lst = vbPost.getWithKey(id);
|
||||||
if (lst == null) {
|
if (lst == null) {
|
||||||
vbPost.addWithKey(lst = new ArrayList<Integer>(), id);
|
vbPost.addWithKey(lst = new ArrayList<>(), id);
|
||||||
}
|
}
|
||||||
lst.add(id);
|
lst.add(id);
|
||||||
}
|
}
|
||||||
@ -466,14 +453,12 @@ public class DomHelper {
|
|||||||
|
|
||||||
Set<Integer> setExtPosts = mapExtPost.get(headid);
|
Set<Integer> setExtPosts = mapExtPost.get(headid);
|
||||||
|
|
||||||
for (int i = 0; i < posts.size(); i++) {
|
for (Integer postId : posts) {
|
||||||
|
if (!postId.equals(headid) && !setExtPosts.contains(postId)) {
|
||||||
Integer postid = posts.get(i);
|
|
||||||
if (!postid.equals(headid) && !setExtPosts.contains(postid)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement post = stats.getWithKey(postid);
|
Statement post = stats.getWithKey(postId);
|
||||||
|
|
||||||
if (post == null) { // possible in case of an inherited postdominance set
|
if (post == null) { // possible in case of an inherited postdominance set
|
||||||
continue;
|
continue;
|
||||||
@ -481,11 +466,11 @@ public class DomHelper {
|
|||||||
|
|
||||||
boolean same = (post == head);
|
boolean same = (post == head);
|
||||||
|
|
||||||
HashSet<Statement> setNodes = new HashSet<Statement>();
|
HashSet<Statement> setNodes = new HashSet<>();
|
||||||
HashSet<Statement> setPreds = new HashSet<Statement>();
|
HashSet<Statement> setPreds = new HashSet<>();
|
||||||
|
|
||||||
// collect statement nodes
|
// collect statement nodes
|
||||||
HashSet<Statement> setHandlers = new HashSet<Statement>();
|
HashSet<Statement> setHandlers = new HashSet<>();
|
||||||
setHandlers.add(head);
|
setHandlers.add(head);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
@ -503,7 +488,7 @@ public class DomHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addhd) {
|
if (addhd) {
|
||||||
LinkedList<Statement> lstStack = new LinkedList<Statement>();
|
LinkedList<Statement> lstStack = new LinkedList<>();
|
||||||
lstStack.add(handler);
|
lstStack.add(handler);
|
||||||
|
|
||||||
while (!lstStack.isEmpty()) {
|
while (!lstStack.isEmpty()) {
|
||||||
@ -552,14 +537,14 @@ public class DomHelper {
|
|||||||
|
|
||||||
// build statement and return
|
// build statement and return
|
||||||
if (excok) {
|
if (excok) {
|
||||||
Statement res = null;
|
Statement res;
|
||||||
|
|
||||||
setPreds.removeAll(setNodes);
|
setPreds.removeAll(setNodes);
|
||||||
if (setPreds.size() == 0) {
|
if (setPreds.size() == 0) {
|
||||||
if ((setNodes.size() > 1 ||
|
if ((setNodes.size() > 1 ||
|
||||||
head.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).contains(head))
|
head.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).contains(head))
|
||||||
&& setNodes.size() < stats.size()) {
|
&& setNodes.size() < stats.size()) {
|
||||||
if (checkSynchronizedCompleteness(head, setNodes)) {
|
if (checkSynchronizedCompleteness(setNodes)) {
|
||||||
res = new GeneralStatement(head, setNodes, same ? null : post);
|
res = new GeneralStatement(head, setNodes, same ? null : post);
|
||||||
stat.collapseNodesToStatement(res);
|
stat.collapseNodesToStatement(res);
|
||||||
|
|
||||||
@ -574,8 +559,7 @@ public class DomHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkSynchronizedCompleteness(Statement head, HashSet<Statement> setNodes) {
|
private static boolean checkSynchronizedCompleteness(Set<Statement> setNodes) {
|
||||||
|
|
||||||
// check exit nodes
|
// check exit nodes
|
||||||
for (Statement stat : setNodes) {
|
for (Statement stat : setNodes) {
|
||||||
if (stat.isMonitorEnter()) {
|
if (stat.isMonitorEnter()) {
|
||||||
@ -617,26 +601,21 @@ public class DomHelper {
|
|||||||
|
|
||||||
// update the postdominator map
|
// update the postdominator map
|
||||||
if (!mapExtPost.isEmpty()) {
|
if (!mapExtPost.isEmpty()) {
|
||||||
HashSet<Integer> setOldNodes = new HashSet<Integer>();
|
HashSet<Integer> setOldNodes = new HashSet<>();
|
||||||
for (Statement old : result.getStats()) {
|
for (Statement old : result.getStats()) {
|
||||||
setOldNodes.add(old.id);
|
setOldNodes.add(old.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer newid = result.id;
|
Integer newid = result.id;
|
||||||
|
|
||||||
for (Integer key : new ArrayList<Integer>(mapExtPost.keySet())) {
|
for (Integer key : new ArrayList<>(mapExtPost.keySet())) {
|
||||||
Set<Integer> set = mapExtPost.get(key);
|
Set<Integer> set = mapExtPost.get(key);
|
||||||
|
|
||||||
int oldsize = set.size();
|
int oldsize = set.size();
|
||||||
set.removeAll(setOldNodes);
|
set.removeAll(setOldNodes);
|
||||||
|
|
||||||
if (setOldNodes.contains(key)) {
|
if (setOldNodes.contains(key)) {
|
||||||
Set<Integer> setNew = mapExtPost.get(newid);
|
mapExtPost.computeIfAbsent(newid, k -> new HashSet<>()).addAll(set);
|
||||||
if (setNew == null) {
|
|
||||||
mapExtPost.put(newid, setNew = new HashSet<Integer>());
|
|
||||||
}
|
|
||||||
setNew.addAll(set);
|
|
||||||
|
|
||||||
mapExtPost.remove(key);
|
mapExtPost.remove(key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
public class EliminateLoopsHelper {
|
|
||||||
|
|
||||||
|
|
||||||
// public static boolean eliminateLoops(Statement root) {
|
|
||||||
//
|
|
||||||
// boolean ret = eliminateLoopsRec(root);
|
|
||||||
//
|
|
||||||
// if(ret) {
|
|
||||||
// SequenceHelper.condenseSequences(root);
|
|
||||||
//
|
|
||||||
// HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
|
|
||||||
//
|
|
||||||
// SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(false);
|
|
||||||
// while(sehelper.simplifyStackVarsStatement(root, setReorderedIfs, null)) {
|
|
||||||
// SequenceHelper.condenseSequences(root);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return ret;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static boolean eliminateLoopsRec(Statement stat) {
|
|
||||||
|
|
||||||
for (Statement st : stat.getStats()) {
|
|
||||||
if (eliminateLoopsRec(st)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat.type == Statement.TYPE_DO && isLoopRedundant((DoStatement)stat)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isLoopRedundant(DoStatement loop) {
|
|
||||||
|
|
||||||
if (loop.getLooptype() != DoStatement.LOOP_DO) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get parent loop if exists
|
|
||||||
Statement parentloop = loop.getParent();
|
|
||||||
while (parentloop != null && parentloop.type != Statement.TYPE_DO) {
|
|
||||||
parentloop = parentloop.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentloop == null || parentloop.getBasichead() != loop.getBasichead()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// collect relevant break edges
|
|
||||||
List<StatEdge> lstBreakEdges = new ArrayList<StatEdge>();
|
|
||||||
for (StatEdge edge : loop.getLabelEdges()) {
|
|
||||||
if (edge.getType() == StatEdge.TYPE_BREAK) { // all break edges are explicit because of LOOP_DO type
|
|
||||||
lstBreakEdges.add(edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Statement loopcontent = loop.getFirst();
|
|
||||||
|
|
||||||
boolean firstok = loopcontent.getAllSuccessorEdges().isEmpty();
|
|
||||||
if (!firstok) {
|
|
||||||
StatEdge edge = loopcontent.getAllSuccessorEdges().get(0);
|
|
||||||
firstok = (edge.closure == loop && edge.getType() == StatEdge.TYPE_BREAK);
|
|
||||||
if (firstok) {
|
|
||||||
lstBreakEdges.remove(edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!lstBreakEdges.isEmpty()) {
|
|
||||||
if (firstok) {
|
|
||||||
|
|
||||||
HashMap<Integer, Boolean> statLabeled = new HashMap<Integer, Boolean>();
|
|
||||||
List<Statement> lstEdgeClosures = new ArrayList<Statement>();
|
|
||||||
|
|
||||||
for (StatEdge edge : lstBreakEdges) {
|
|
||||||
Statement minclosure = LowBreakHelper.getMinClosure(loopcontent, edge.getSource());
|
|
||||||
lstEdgeClosures.add(minclosure);
|
|
||||||
}
|
|
||||||
|
|
||||||
int precount = loop.isLabeled() ? 1 : 0;
|
|
||||||
for (Statement st : lstEdgeClosures) {
|
|
||||||
if (!statLabeled.containsKey(st.id)) {
|
|
||||||
boolean btemp = st.isLabeled();
|
|
||||||
precount += btemp ? 1 : 0;
|
|
||||||
statLabeled.put(st.id, btemp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < lstBreakEdges.size(); i++) {
|
|
||||||
Statement st = lstEdgeClosures.get(i);
|
|
||||||
statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < lstBreakEdges.size(); i++) {
|
|
||||||
lstEdgeClosures.set(i, getMaxBreakLift(lstEdgeClosures.get(i), lstBreakEdges.get(i), statLabeled, loop));
|
|
||||||
}
|
|
||||||
|
|
||||||
statLabeled.clear();
|
|
||||||
for (Statement st : lstEdgeClosures) {
|
|
||||||
statLabeled.put(st.id, st.isLabeled());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < lstBreakEdges.size(); i++) {
|
|
||||||
Statement st = lstEdgeClosures.get(i);
|
|
||||||
statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
int postcount = 0;
|
|
||||||
for (Boolean val : statLabeled.values()) {
|
|
||||||
postcount += val ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (precount <= postcount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < lstBreakEdges.size(); i++) {
|
|
||||||
lstEdgeClosures.get(i).addLabeledEdge(lstBreakEdges.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eliminateLoop(loop, parentloop);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Statement getMaxBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
|
|
||||||
|
|
||||||
Statement closure = stat;
|
|
||||||
Statement newclosure = stat;
|
|
||||||
|
|
||||||
while ((newclosure = getNextBreakLift(newclosure, edge, statLabeled, max)) != null) {
|
|
||||||
closure = newclosure;
|
|
||||||
}
|
|
||||||
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Statement getNextBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
|
|
||||||
|
|
||||||
Statement closure = stat.getParent();
|
|
||||||
|
|
||||||
while (closure != null && closure != max && !closure.containsStatementStrict(edge.getDestination())) {
|
|
||||||
|
|
||||||
boolean edge_labeled = LowBreakHelper.isBreakEdgeLabeled(edge.getSource(), closure);
|
|
||||||
boolean stat_labeled = statLabeled.containsKey(closure.id) ? statLabeled.get(closure.id) : closure.isLabeled();
|
|
||||||
|
|
||||||
if (stat_labeled || !edge_labeled) {
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
closure = closure.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void eliminateLoop(Statement loop, Statement parentloop) {
|
|
||||||
|
|
||||||
// move continue edges to the parent loop
|
|
||||||
List<StatEdge> lst = new ArrayList<StatEdge>(loop.getLabelEdges());
|
|
||||||
for (StatEdge edge : lst) {
|
|
||||||
loop.removePredecessor(edge);
|
|
||||||
edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, parentloop);
|
|
||||||
parentloop.addPredecessor(edge);
|
|
||||||
|
|
||||||
parentloop.addLabeledEdge(edge);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the last break edge, if exists
|
|
||||||
Statement loopcontent = loop.getFirst();
|
|
||||||
if (!loopcontent.getAllSuccessorEdges().isEmpty()) {
|
|
||||||
loopcontent.removeSuccessor(loopcontent.getAllSuccessorEdges().get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace loop with its content
|
|
||||||
loop.getParent().replaceStatement(loop, loopcontent);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
||||||
@ -21,40 +7,30 @@ import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ExitHelper {
|
public final class ExitHelper {
|
||||||
|
|
||||||
|
|
||||||
public static boolean condenseExits(RootStatement root) {
|
public static boolean condenseExits(RootStatement root) {
|
||||||
|
|
||||||
int changed = integrateExits(root);
|
int changed = integrateExits(root);
|
||||||
|
|
||||||
if (changed > 0) {
|
if (changed > 0) {
|
||||||
|
|
||||||
cleanUpUnreachableBlocks(root);
|
cleanUpUnreachableBlocks(root);
|
||||||
|
|
||||||
SequenceHelper.condenseSequences(root);
|
SequenceHelper.condenseSequences(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (changed > 0);
|
return (changed > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void cleanUpUnreachableBlocks(Statement stat) {
|
private static void cleanUpUnreachableBlocks(Statement stat) {
|
||||||
|
|
||||||
boolean found;
|
boolean found;
|
||||||
do {
|
do {
|
||||||
|
|
||||||
found = false;
|
found = false;
|
||||||
|
|
||||||
for (int i = 0; i < stat.getStats().size(); i++) {
|
for (int i = 0; i < stat.getStats().size(); i++) {
|
||||||
|
|
||||||
Statement st = stat.getStats().get(i);
|
Statement st = stat.getStats().get(i);
|
||||||
|
|
||||||
cleanUpUnreachableBlocks(st);
|
cleanUpUnreachableBlocks(st);
|
||||||
@ -71,7 +47,7 @@ public class ExitHelper {
|
|||||||
set.remove(secondlast);
|
set.remove(secondlast);
|
||||||
|
|
||||||
if (set.isEmpty()) {
|
if (set.isEmpty()) {
|
||||||
last.setExprents(new ArrayList<Exprent>());
|
last.setExprents(new ArrayList<>());
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -83,16 +59,12 @@ public class ExitHelper {
|
|||||||
while (found);
|
while (found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static int integrateExits(Statement stat) {
|
private static int integrateExits(Statement stat) {
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
Statement dest = null;
|
Statement dest;
|
||||||
|
|
||||||
if (stat.getExprents() == null) {
|
if (stat.getExprents() == null) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
|
||||||
for (Statement st : stat.getStats()) {
|
for (Statement st : stat.getStats()) {
|
||||||
@ -108,33 +80,31 @@ public class ExitHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stat.type == Statement.TYPE_IF) {
|
||||||
|
IfStatement ifst = (IfStatement)stat;
|
||||||
|
if (ifst.getIfstat() == null) {
|
||||||
|
StatEdge ifedge = ifst.getIfEdge();
|
||||||
|
dest = isExitEdge(ifedge);
|
||||||
|
if (dest != null) {
|
||||||
|
BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
|
||||||
|
DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
|
||||||
|
bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
|
||||||
|
|
||||||
switch (stat.type) {
|
ifst.getFirst().removeSuccessor(ifedge);
|
||||||
case Statement.TYPE_IF:
|
StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
|
||||||
IfStatement ifst = (IfStatement)stat;
|
ifst.getFirst().addSuccessor(newedge);
|
||||||
if (ifst.getIfstat() == null) {
|
ifst.setIfEdge(newedge);
|
||||||
StatEdge ifedge = ifst.getIfEdge();
|
ifst.setIfstat(bstat);
|
||||||
dest = isExitEdge(ifedge);
|
ifst.getStats().addWithKey(bstat, bstat.id);
|
||||||
if (dest != null) {
|
bstat.setParent(ifst);
|
||||||
BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
|
|
||||||
DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
|
|
||||||
bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
|
|
||||||
|
|
||||||
ifst.getFirst().removeSuccessor(ifedge);
|
StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
|
||||||
StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
|
StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
|
||||||
ifst.getFirst().addSuccessor(newedge);
|
bstat.addSuccessor(newexitedge);
|
||||||
ifst.setIfEdge(newedge);
|
oldexitedge.closure.addLabeledEdge(newexitedge);
|
||||||
ifst.setIfstat(bstat);
|
ret = 1;
|
||||||
ifst.getStats().addWithKey(bstat, bstat.id);
|
|
||||||
bstat.setParent(ifst);
|
|
||||||
|
|
||||||
StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
|
|
||||||
StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
|
|
||||||
bstat.addSuccessor(newexitedge);
|
|
||||||
oldexitedge.closure.addLabeledEdge(newexitedge);
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,15 +138,12 @@ public class ExitHelper {
|
|||||||
// LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
|
// LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
|
||||||
// do it by hand
|
// do it by hand
|
||||||
for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
|
for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
|
||||||
|
|
||||||
block.removePredecessor(prededge);
|
block.removePredecessor(prededge);
|
||||||
prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, stat);
|
prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, stat);
|
||||||
stat.addPredecessor(prededge);
|
stat.addPredecessor(prededge);
|
||||||
|
|
||||||
stat.addLabeledEdge(prededge);
|
stat.addLabeledEdge(prededge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, bstat));
|
stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, bstat));
|
||||||
|
|
||||||
for (StatEdge edge : dest.getAllPredecessorEdges()) {
|
for (StatEdge edge : dest.getAllPredecessorEdges()) {
|
||||||
@ -202,11 +169,9 @@ public class ExitHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Statement isExitEdge(StatEdge edge) {
|
private static Statement isExitEdge(StatEdge edge) {
|
||||||
|
|
||||||
Statement dest = edge.getDestination();
|
Statement dest = edge.getDestination();
|
||||||
|
|
||||||
if (edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK
|
if (edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK && edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
|
||||||
&& edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
|
|
||||||
List<Exprent> data = dest.getExprents();
|
List<Exprent> data = dest.getExprents();
|
||||||
|
|
||||||
if (data != null && data.size() == 1) {
|
if (data != null && data.size() == 1) {
|
||||||
@ -220,7 +185,6 @@ public class ExitHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isOnlyEdge(StatEdge edge) {
|
private static boolean isOnlyEdge(StatEdge edge) {
|
||||||
|
|
||||||
Statement stat = edge.getDestination();
|
Statement stat = edge.getDestination();
|
||||||
|
|
||||||
for (StatEdge ed : stat.getAllPredecessorEdges()) {
|
for (StatEdge ed : stat.getAllPredecessorEdges()) {
|
||||||
@ -243,11 +207,10 @@ public class ExitHelper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean removeRedundantReturns(RootStatement root) {
|
public static void removeRedundantReturns(RootStatement root) {
|
||||||
|
DummyExitStatement dummyExit = root.getDummyExit();
|
||||||
|
|
||||||
boolean res = false;
|
for (StatEdge edge : dummyExit.getAllPredecessorEdges()) {
|
||||||
|
|
||||||
for (StatEdge edge : root.getDummyExit().getAllPredecessorEdges()) {
|
|
||||||
if (!edge.explicit) {
|
if (!edge.explicit) {
|
||||||
Statement source = edge.getSource();
|
Statement source = edge.getSource();
|
||||||
List<Exprent> lstExpr = source.getExprents();
|
List<Exprent> lstExpr = source.getExprents();
|
||||||
@ -255,91 +218,14 @@ public class ExitHelper {
|
|||||||
Exprent expr = lstExpr.get(lstExpr.size() - 1);
|
Exprent expr = lstExpr.get(lstExpr.size() - 1);
|
||||||
if (expr.type == Exprent.EXPRENT_EXIT) {
|
if (expr.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent ex = (ExitExprent)expr;
|
ExitExprent ex = (ExitExprent)expr;
|
||||||
if (ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
|
if (ex.getExitType() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
|
||||||
// remove redundant return
|
// remove redundant return
|
||||||
|
dummyExit.addBytecodeOffsets(ex.bytecode);
|
||||||
lstExpr.remove(lstExpr.size() - 1);
|
lstExpr.remove(lstExpr.size() - 1);
|
||||||
res = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public static boolean handleReturnFromInitializer(RootStatement root) {
|
|
||||||
|
|
||||||
boolean res = false;
|
|
||||||
|
|
||||||
Statement exit = root.getDummyExit();
|
|
||||||
Statement top = root.getFirst();
|
|
||||||
Statement newret = null;
|
|
||||||
|
|
||||||
boolean sharedcreated = false;
|
|
||||||
|
|
||||||
for (StatEdge edge : exit.getAllPredecessorEdges()) {
|
|
||||||
if (edge.explicit) {
|
|
||||||
|
|
||||||
if (!sharedcreated) {
|
|
||||||
newret = addSharedInitializerReturn(root);
|
|
||||||
sharedcreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement source = edge.getSource();
|
|
||||||
List<Exprent> lstExpr = source.getExprents();
|
|
||||||
if (lstExpr != null && !lstExpr.isEmpty()) {
|
|
||||||
Exprent expr = lstExpr.get(lstExpr.size() - 1);
|
|
||||||
if (expr.type == Exprent.EXPRENT_EXIT) {
|
|
||||||
ExitExprent ex = (ExitExprent)expr;
|
|
||||||
if (ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
|
|
||||||
lstExpr.remove(lstExpr.size() - 1);
|
|
||||||
|
|
||||||
source.removeSuccessor(edge);
|
|
||||||
source.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, source, newret, top));
|
|
||||||
|
|
||||||
res = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Statement addSharedInitializerReturn(RootStatement root) {
|
|
||||||
|
|
||||||
Statement exit = root.getDummyExit();
|
|
||||||
Statement top = root.getFirst();
|
|
||||||
|
|
||||||
// build a new statement with the single instruction 'return'
|
|
||||||
BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
|
|
||||||
DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
|
|
||||||
|
|
||||||
ExitExprent retexpr = new ExitExprent(ExitExprent.EXIT_RETURN, null,
|
|
||||||
((MethodDescriptor)DecompilerContext
|
|
||||||
.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret);
|
|
||||||
// a changeable list needed
|
|
||||||
bstat.setExprents(new ArrayList<Exprent>(Arrays.asList(new Exprent[]{retexpr})));
|
|
||||||
|
|
||||||
// build sequence to replace the former top statement
|
|
||||||
SequenceStatement seq = new SequenceStatement(Arrays.asList(top, bstat));
|
|
||||||
top.setParent(seq);
|
|
||||||
bstat.setParent(seq);
|
|
||||||
seq.setParent(root);
|
|
||||||
|
|
||||||
root.getStats().removeWithKey(top.id);
|
|
||||||
root.getStats().addWithKeyAndIndex(0, seq, seq.id);
|
|
||||||
root.setFirst(seq);
|
|
||||||
|
|
||||||
for (StatEdge succedge : top.getAllSuccessorEdges()) {
|
|
||||||
top.removeSuccessor(succedge);
|
|
||||||
}
|
|
||||||
|
|
||||||
top.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, top, bstat));
|
|
||||||
bstat.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, bstat, exit, seq));
|
|
||||||
|
|
||||||
return bstat;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -20,7 +6,7 @@ import org.jetbrains.java.decompiler.code.Instruction;
|
|||||||
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
||||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
import org.jetbrains.java.decompiler.main.TextBuffer;
|
import org.jetbrains.java.decompiler.util.TextBuffer;
|
||||||
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
|
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
|
import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
|
||||||
@ -38,152 +24,115 @@ import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
|
|||||||
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
|
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.jetbrains.java.decompiler.util.SortUtil;
|
|
||||||
import org.jetbrains.java.decompiler.util.Util;
|
|
||||||
|
|
||||||
public class ExprProcessor implements CodeConstants {
|
public class ExprProcessor implements CodeConstants {
|
||||||
|
|
||||||
public static final String UNDEFINED_TYPE_STRING = "<undefinedtype>";
|
public static final String UNDEFINED_TYPE_STRING = "<undefinedtype>";
|
||||||
public static final String UNKNOWN_TYPE_STRING = "<unknown>";
|
public static final String UNKNOWN_TYPE_STRING = "<unknown>";
|
||||||
public static final String NULL_TYPE_STRING = "<null>";
|
public static final String NULL_TYPE_STRING = "<null>";
|
||||||
|
|
||||||
private static final HashMap<Integer, Integer> mapConsts = new HashMap<Integer, Integer>();
|
private static final Map<Integer, Integer> mapConsts = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
mapConsts.put(opc_arraylength, FunctionExprent.FUNCTION_ARRAY_LENGTH);
|
||||||
// mapConsts.put(new Integer(opc_i2l), new
|
mapConsts.put(opc_checkcast, FunctionExprent.FUNCTION_CAST);
|
||||||
// Integer(FunctionExprent.FUNCTION_I2L));
|
mapConsts.put(opc_instanceof, FunctionExprent.FUNCTION_INSTANCEOF);
|
||||||
// mapConsts.put(new Integer(opc_i2f), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_I2F));
|
|
||||||
// mapConsts.put(new Integer(opc_i2d), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_I2D));
|
|
||||||
// mapConsts.put(new Integer(opc_l2i), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_L2I));
|
|
||||||
// mapConsts.put(new Integer(opc_l2f), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_L2F));
|
|
||||||
// mapConsts.put(new Integer(opc_l2d), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_L2D));
|
|
||||||
// mapConsts.put(new Integer(opc_f2i), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_F2I));
|
|
||||||
// mapConsts.put(new Integer(opc_f2l), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_F2L));
|
|
||||||
// mapConsts.put(new Integer(opc_f2d), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_F2D));
|
|
||||||
// mapConsts.put(new Integer(opc_d2i), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_D2I));
|
|
||||||
// mapConsts.put(new Integer(opc_d2l), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_D2L));
|
|
||||||
// mapConsts.put(new Integer(opc_d2f), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_D2F));
|
|
||||||
// mapConsts.put(new Integer(opc_i2b), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_I2B));
|
|
||||||
// mapConsts.put(new Integer(opc_i2c), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_I2C));
|
|
||||||
// mapConsts.put(new Integer(opc_i2s), new
|
|
||||||
// Integer(FunctionExprent.FUNCTION_I2S));
|
|
||||||
|
|
||||||
mapConsts.put(new Integer(opc_arraylength), new Integer(FunctionExprent.FUNCTION_ARRAYLENGTH));
|
|
||||||
mapConsts.put(new Integer(opc_checkcast), new Integer(FunctionExprent.FUNCTION_CAST));
|
|
||||||
mapConsts.put(new Integer(opc_instanceof), new Integer(FunctionExprent.FUNCTION_INSTANCEOF));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final VarType[] consts =
|
private static final VarType[] consts = {
|
||||||
new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS,
|
VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS, VarType.VARTYPE_STRING
|
||||||
VarType.VARTYPE_STRING};
|
};
|
||||||
|
|
||||||
private static final VarType[] vartypes =
|
private static final VarType[] varTypes = {
|
||||||
new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT};
|
VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT
|
||||||
|
};
|
||||||
|
|
||||||
private static final VarType[] arrtypes =
|
private static final VarType[] arrTypes = {
|
||||||
new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
|
VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
|
||||||
VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT};
|
VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT
|
||||||
|
};
|
||||||
|
|
||||||
private static final int[] func1 =
|
private static final int[] func1 = {
|
||||||
new int[]{FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
|
FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
|
||||||
FunctionExprent.FUNCTION_REM};
|
FunctionExprent.FUNCTION_REM
|
||||||
|
};
|
||||||
|
private static final int[] func2 = {
|
||||||
|
FunctionExprent.FUNCTION_SHL, FunctionExprent.FUNCTION_SHR, FunctionExprent.FUNCTION_USHR, FunctionExprent.FUNCTION_AND,
|
||||||
|
FunctionExprent.FUNCTION_OR, FunctionExprent.FUNCTION_XOR
|
||||||
|
};
|
||||||
|
private static final int[] func3 = {
|
||||||
|
FunctionExprent.FUNCTION_I2L, FunctionExprent.FUNCTION_I2F, FunctionExprent.FUNCTION_I2D, FunctionExprent.FUNCTION_L2I,
|
||||||
|
FunctionExprent.FUNCTION_L2F, FunctionExprent.FUNCTION_L2D, FunctionExprent.FUNCTION_F2I, FunctionExprent.FUNCTION_F2L,
|
||||||
|
FunctionExprent.FUNCTION_F2D, FunctionExprent.FUNCTION_D2I, FunctionExprent.FUNCTION_D2L, FunctionExprent.FUNCTION_D2F,
|
||||||
|
FunctionExprent.FUNCTION_I2B, FunctionExprent.FUNCTION_I2C, FunctionExprent.FUNCTION_I2S
|
||||||
|
};
|
||||||
|
private static final int[] func4 = {
|
||||||
|
FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL,
|
||||||
|
FunctionExprent.FUNCTION_DCMPG
|
||||||
|
};
|
||||||
|
private static final int[] func5 = {
|
||||||
|
IfExprent.IF_EQ, IfExprent.IF_NE, IfExprent.IF_LT, IfExprent.IF_GE, IfExprent.IF_GT, IfExprent.IF_LE
|
||||||
|
};
|
||||||
|
private static final int[] func6 = {
|
||||||
|
IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPGT, IfExprent.IF_ICMPLE,
|
||||||
|
IfExprent.IF_ACMPEQ, IfExprent.IF_ACMPNE
|
||||||
|
};
|
||||||
|
private static final int[] func7 = {IfExprent.IF_NULL, IfExprent.IF_NONNULL};
|
||||||
|
private static final int[] func8 = {MonitorExprent.MONITOR_ENTER, MonitorExprent.MONITOR_EXIT};
|
||||||
|
|
||||||
private static final int[] func2 =
|
private static final int[] arrTypeIds = {
|
||||||
new int[]{FunctionExprent.FUNCTION_SHL, FunctionExprent.FUNCTION_SHR, FunctionExprent.FUNCTION_USHR, FunctionExprent.FUNCTION_AND,
|
CodeConstants.TYPE_BOOLEAN, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_DOUBLE,
|
||||||
FunctionExprent.FUNCTION_OR, FunctionExprent.FUNCTION_XOR};
|
CodeConstants.TYPE_BYTE, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG
|
||||||
|
};
|
||||||
|
|
||||||
private static final int[] func3 =
|
private static final int[] negIfs = {
|
||||||
new int[]{FunctionExprent.FUNCTION_I2L, FunctionExprent.FUNCTION_I2F, FunctionExprent.FUNCTION_I2D, FunctionExprent.FUNCTION_L2I,
|
IfExprent.IF_NE, IfExprent.IF_EQ, IfExprent.IF_GE, IfExprent.IF_LT, IfExprent.IF_LE, IfExprent.IF_GT, IfExprent.IF_NONNULL,
|
||||||
FunctionExprent.FUNCTION_L2F, FunctionExprent.FUNCTION_L2D, FunctionExprent.FUNCTION_F2I, FunctionExprent.FUNCTION_F2L,
|
IfExprent.IF_NULL, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPLE,
|
||||||
FunctionExprent.FUNCTION_F2D,
|
IfExprent.IF_ICMPGT, IfExprent.IF_ACMPNE, IfExprent.IF_ACMPEQ
|
||||||
FunctionExprent.FUNCTION_D2I, FunctionExprent.FUNCTION_D2L, FunctionExprent.FUNCTION_D2F, FunctionExprent.FUNCTION_I2B,
|
};
|
||||||
FunctionExprent.FUNCTION_I2C,
|
|
||||||
FunctionExprent.FUNCTION_I2S};
|
|
||||||
|
|
||||||
private static final int[] func4 =
|
private static final String[] typeNames = {"byte", "char", "double", "float", "int", "long", "short", "boolean"};
|
||||||
new int[]{FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL,
|
|
||||||
FunctionExprent.FUNCTION_DCMPG};
|
|
||||||
|
|
||||||
private static final int[] func5 =
|
private final MethodDescriptor methodDescriptor;
|
||||||
new int[]{IfExprent.IF_EQ, IfExprent.IF_NE, IfExprent.IF_LT, IfExprent.IF_GE, IfExprent.IF_GT, IfExprent.IF_LE};
|
private final VarProcessor varProcessor;
|
||||||
|
|
||||||
private static final int[] func6 =
|
public ExprProcessor(MethodDescriptor md, VarProcessor varProc) {
|
||||||
new int[]{IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPGT, IfExprent.IF_ICMPLE,
|
methodDescriptor = md;
|
||||||
IfExprent.IF_ACMPEQ, IfExprent.IF_ACMPNE};
|
varProcessor = varProc;
|
||||||
|
}
|
||||||
private static final int[] func7 = new int[]{IfExprent.IF_NULL, IfExprent.IF_NONNULL};
|
|
||||||
|
|
||||||
private static final int[] func8 = new int[]{MonitorExprent.MONITOR_ENTER, MonitorExprent.MONITOR_EXIT};
|
|
||||||
|
|
||||||
private static final int[] arr_type =
|
|
||||||
new int[]{CodeConstants.TYPE_BOOLEAN, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_DOUBLE,
|
|
||||||
CodeConstants.TYPE_BYTE, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG};
|
|
||||||
|
|
||||||
private static final int[] negifs =
|
|
||||||
new int[]{IfExprent.IF_NE, IfExprent.IF_EQ, IfExprent.IF_GE, IfExprent.IF_LT, IfExprent.IF_LE, IfExprent.IF_GT, IfExprent.IF_NONNULL,
|
|
||||||
IfExprent.IF_NULL, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPLE,
|
|
||||||
IfExprent.IF_ICMPGT, IfExprent.IF_ACMPNE,
|
|
||||||
IfExprent.IF_ACMPEQ};
|
|
||||||
|
|
||||||
private static final String[] typeNames = new String[]{"byte", "char", "double", "float", "int", "long", "short", "boolean",};
|
|
||||||
|
|
||||||
private VarProcessor varProcessor = (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
|
|
||||||
|
|
||||||
public void processStatement(RootStatement root, StructClass cl) {
|
public void processStatement(RootStatement root, StructClass cl) {
|
||||||
|
|
||||||
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
||||||
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
||||||
|
|
||||||
// try {
|
|
||||||
// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
|
|
||||||
// } catch (Exception ex) {
|
|
||||||
// ex.printStackTrace();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// collect finally entry points
|
// collect finally entry points
|
||||||
Set<String> setFinallyShortRangeEntryPoints = new HashSet<String>();
|
Set<String> setFinallyShortRangeEntryPoints = new HashSet<>();
|
||||||
for (List<FinallyPathWrapper> lst : dgraph.mapShortRangeFinallyPaths.values()) {
|
for (List<FinallyPathWrapper> lst : dgraph.mapShortRangeFinallyPaths.values()) {
|
||||||
for (FinallyPathWrapper finwrap : lst) {
|
for (FinallyPathWrapper finwrap : lst) {
|
||||||
setFinallyShortRangeEntryPoints.add(finwrap.entry);
|
setFinallyShortRangeEntryPoints.add(finwrap.entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> setFinallyLongRangeEntryPaths = new HashSet<String>();
|
Set<String> setFinallyLongRangeEntryPaths = new HashSet<>();
|
||||||
for (List<FinallyPathWrapper> lst : dgraph.mapLongRangeFinallyPaths.values()) {
|
for (List<FinallyPathWrapper> lst : dgraph.mapLongRangeFinallyPaths.values()) {
|
||||||
for (FinallyPathWrapper finwrap : lst) {
|
for (FinallyPathWrapper finwrap : lst) {
|
||||||
setFinallyLongRangeEntryPaths.add(finwrap.source + "##" + finwrap.entry);
|
setFinallyLongRangeEntryPaths.add(finwrap.source + "##" + finwrap.entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, VarExprent> mapCatch = new HashMap<String, VarExprent>();
|
Map<String, VarExprent> mapCatch = new HashMap<>();
|
||||||
collectCatchVars(root, flatthelper, mapCatch);
|
collectCatchVars(root, flatthelper, mapCatch);
|
||||||
|
|
||||||
Map<DirectNode, Map<String, PrimitiveExprsList>> mapData = new HashMap<DirectNode, Map<String, PrimitiveExprsList>>();
|
Map<DirectNode, Map<String, PrimitiveExprsList>> mapData = new HashMap<>();
|
||||||
|
|
||||||
LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
|
LinkedList<DirectNode> stack = new LinkedList<>();
|
||||||
LinkedList<LinkedList<String>> stackEntryPoint = new LinkedList<LinkedList<String>>();
|
LinkedList<LinkedList<String>> stackEntryPoint = new LinkedList<>();
|
||||||
|
|
||||||
stack.add(dgraph.first);
|
stack.add(dgraph.first);
|
||||||
stackEntryPoint.add(new LinkedList<String>());
|
stackEntryPoint.add(new LinkedList<>());
|
||||||
|
|
||||||
Map<String, PrimitiveExprsList> map = new HashMap<String, PrimitiveExprsList>();
|
Map<String, PrimitiveExprsList> map = new HashMap<>();
|
||||||
map.put(null, new PrimitiveExprsList());
|
map.put(null, new PrimitiveExprsList());
|
||||||
mapData.put(dgraph.first, map);
|
mapData.put(dgraph.first, map);
|
||||||
|
|
||||||
@ -222,13 +171,8 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isSuccessor) {
|
if (isSuccessor) {
|
||||||
|
Map<String, PrimitiveExprsList> mapSucc = mapData.computeIfAbsent(nd, k -> new HashMap<>());
|
||||||
Map<String, PrimitiveExprsList> mapSucc = mapData.get(nd);
|
LinkedList<String> ndentrypoints = new LinkedList<>(entrypoints);
|
||||||
if (mapSucc == null) {
|
|
||||||
mapData.put(nd, mapSucc = new HashMap<String, PrimitiveExprsList>());
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkedList<String> ndentrypoints = new LinkedList<String>(entrypoints);
|
|
||||||
|
|
||||||
if (setFinallyLongRangeEntryPaths.contains(node.id + "##" + nd.id)) {
|
if (setFinallyLongRangeEntryPaths.contains(node.id + "##" + nd.id)) {
|
||||||
ndentrypoints.addLast(node.id);
|
ndentrypoints.addLast(node.id);
|
||||||
@ -279,10 +223,14 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
|
|
||||||
private static PrimitiveExprsList copyVarExprents(PrimitiveExprsList data) {
|
private static PrimitiveExprsList copyVarExprents(PrimitiveExprsList data) {
|
||||||
ExprentStack stack = data.getStack();
|
ExprentStack stack = data.getStack();
|
||||||
|
copyEntries(stack);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copyEntries(List<Exprent> stack) {
|
||||||
for (int i = 0; i < stack.size(); i++) {
|
for (int i = 0; i < stack.size(); i++) {
|
||||||
stack.set(i, stack.get(i).copy());
|
stack.set(i, stack.get(i).copy());
|
||||||
}
|
}
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void collectCatchVars(Statement stat, FlattenStatementsHelper flatthelper, Map<String, VarExprent> map) {
|
private static void collectCatchVars(Statement stat, FlattenStatementsHelper flatthelper, Map<String, VarExprent> map) {
|
||||||
@ -321,8 +269,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, StructClass cl) {
|
public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, StructClass cl) {
|
||||||
|
|
||||||
ConstantPool pool = cl.getPool();
|
ConstantPool pool = cl.getPool();
|
||||||
StructBootstrapMethodsAttribute bootstrap =
|
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
||||||
(StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
|
||||||
|
|
||||||
BasicBlock block = stat.getBlock();
|
BasicBlock block = stat.getBlock();
|
||||||
|
|
||||||
@ -335,40 +282,47 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
|
|
||||||
Instruction instr = seq.getInstr(i);
|
Instruction instr = seq.getInstr(i);
|
||||||
Integer bytecode_offset = block.getOldOffset(i);
|
Integer bytecode_offset = block.getOldOffset(i);
|
||||||
|
Set<Integer> bytecode_offsets = bytecode_offset >= 0 ? Collections.singleton(bytecode_offset) : null;
|
||||||
|
|
||||||
switch (instr.opcode) {
|
switch (instr.opcode) {
|
||||||
case opc_aconst_null:
|
case opc_aconst_null:
|
||||||
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_NULL, null));
|
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_NULL, null, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_bipush:
|
case opc_bipush:
|
||||||
case opc_sipush:
|
case opc_sipush:
|
||||||
pushEx(stack, exprlist, new ConstExprent(instr.getOperand(0), true));
|
pushEx(stack, exprlist, new ConstExprent(instr.operand(0), true, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_lconst_0:
|
case opc_lconst_0:
|
||||||
case opc_lconst_1:
|
case opc_lconst_1:
|
||||||
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_LONG, new Long(instr.opcode - opc_lconst_0)));
|
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_LONG, (long)(instr.opcode - opc_lconst_0), bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_fconst_0:
|
case opc_fconst_0:
|
||||||
case opc_fconst_1:
|
case opc_fconst_1:
|
||||||
case opc_fconst_2:
|
case opc_fconst_2:
|
||||||
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_FLOAT, new Float(instr.opcode - opc_fconst_0)));
|
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_FLOAT, (float)(instr.opcode - opc_fconst_0), bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_dconst_0:
|
case opc_dconst_0:
|
||||||
case opc_dconst_1:
|
case opc_dconst_1:
|
||||||
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(instr.opcode - opc_dconst_0)));
|
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_DOUBLE, (double)(instr.opcode - opc_dconst_0), bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_ldc:
|
case opc_ldc:
|
||||||
case opc_ldc_w:
|
case opc_ldc_w:
|
||||||
case opc_ldc2_w:
|
case opc_ldc2_w:
|
||||||
PrimitiveConstant cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
PooledConstant cn = pool.getConstant(instr.operand(0));
|
||||||
pushEx(stack, exprlist, new ConstExprent(consts[cn.type - CONSTANT_Integer], cn.value));
|
if (cn instanceof PrimitiveConstant) {
|
||||||
|
pushEx(stack, exprlist, new ConstExprent(consts[cn.type - CONSTANT_Integer], ((PrimitiveConstant)cn).value, bytecode_offsets));
|
||||||
|
}
|
||||||
|
else if (cn instanceof LinkConstant) {
|
||||||
|
//TODO: for now treat Links as Strings
|
||||||
|
pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_STRING, ((LinkConstant)cn).elementname, bytecode_offsets));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case opc_iload:
|
case opc_iload:
|
||||||
case opc_lload:
|
case opc_lload:
|
||||||
case opc_fload:
|
case opc_fload:
|
||||||
case opc_dload:
|
case opc_dload:
|
||||||
case opc_aload:
|
case opc_aload:
|
||||||
pushEx(stack, exprlist, new VarExprent(instr.getOperand(0), vartypes[instr.opcode - opc_iload], varProcessor));
|
pushEx(stack, exprlist, new VarExprent(instr.operand(0), varTypes[instr.opcode - opc_iload], varProcessor, bytecode_offset));
|
||||||
break;
|
break;
|
||||||
case opc_iaload:
|
case opc_iaload:
|
||||||
case opc_laload:
|
case opc_laload:
|
||||||
@ -389,17 +343,17 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_daload:
|
case opc_daload:
|
||||||
vartype = VarType.VARTYPE_DOUBLE;
|
vartype = VarType.VARTYPE_DOUBLE;
|
||||||
}
|
}
|
||||||
pushEx(stack, exprlist, new ArrayExprent(arr, index, arrtypes[instr.opcode - opc_iaload]), vartype);
|
pushEx(stack, exprlist, new ArrayExprent(arr, index, arrTypes[instr.opcode - opc_iaload], bytecode_offsets), vartype);
|
||||||
break;
|
break;
|
||||||
case opc_istore:
|
case opc_istore:
|
||||||
case opc_lstore:
|
case opc_lstore:
|
||||||
case opc_fstore:
|
case opc_fstore:
|
||||||
case opc_dstore:
|
case opc_dstore:
|
||||||
case opc_astore:
|
case opc_astore:
|
||||||
Exprent top = stack.pop();
|
Exprent expr = stack.pop();
|
||||||
int varindex = instr.getOperand(0);
|
int varindex = instr.operand(0);
|
||||||
AssignmentExprent assign =
|
AssignmentExprent assign = new AssignmentExprent(
|
||||||
new AssignmentExprent(new VarExprent(varindex, vartypes[instr.opcode - opc_istore], varProcessor), top);
|
new VarExprent(varindex, varTypes[instr.opcode - opc_istore], varProcessor, nextMeaningfulOffset(block, i)), expr, bytecode_offsets);
|
||||||
exprlist.add(assign);
|
exprlist.add(assign);
|
||||||
break;
|
break;
|
||||||
case opc_iastore:
|
case opc_iastore:
|
||||||
@ -414,7 +368,8 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
Exprent index_store = stack.pop();
|
Exprent index_store = stack.pop();
|
||||||
Exprent arr_store = stack.pop();
|
Exprent arr_store = stack.pop();
|
||||||
AssignmentExprent arrassign =
|
AssignmentExprent arrassign =
|
||||||
new AssignmentExprent(new ArrayExprent(arr_store, index_store, arrtypes[instr.opcode - opc_iastore]), value);
|
new AssignmentExprent(new ArrayExprent(arr_store, index_store, arrTypes[instr.opcode - opc_iastore], bytecode_offsets), value,
|
||||||
|
bytecode_offsets);
|
||||||
exprlist.add(arrassign);
|
exprlist.add(arrassign);
|
||||||
break;
|
break;
|
||||||
case opc_iadd:
|
case opc_iadd:
|
||||||
@ -437,7 +392,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_lrem:
|
case opc_lrem:
|
||||||
case opc_frem:
|
case opc_frem:
|
||||||
case opc_drem:
|
case opc_drem:
|
||||||
pushEx(stack, exprlist, new FunctionExprent(func1[(instr.opcode - opc_iadd) / 4], stack));
|
pushEx(stack, exprlist, new FunctionExprent(func1[(instr.opcode - opc_iadd) / 4], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_ishl:
|
case opc_ishl:
|
||||||
case opc_lshl:
|
case opc_lshl:
|
||||||
@ -451,19 +406,20 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_lor:
|
case opc_lor:
|
||||||
case opc_ixor:
|
case opc_ixor:
|
||||||
case opc_lxor:
|
case opc_lxor:
|
||||||
pushEx(stack, exprlist, new FunctionExprent(func2[(instr.opcode - opc_ishl) / 2], stack));
|
pushEx(stack, exprlist, new FunctionExprent(func2[(instr.opcode - opc_ishl) / 2], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_ineg:
|
case opc_ineg:
|
||||||
case opc_lneg:
|
case opc_lneg:
|
||||||
case opc_fneg:
|
case opc_fneg:
|
||||||
case opc_dneg:
|
case opc_dneg:
|
||||||
pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack));
|
pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_iinc:
|
case opc_iinc:
|
||||||
VarExprent vevar = new VarExprent(instr.getOperand(0), VarType.VARTYPE_INT, varProcessor);
|
VarExprent vevar = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor);
|
||||||
exprlist.add(new AssignmentExprent(vevar, new FunctionExprent(
|
exprlist.add(new AssignmentExprent(vevar, new FunctionExprent(
|
||||||
instr.getOperand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD, Arrays
|
instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD, Arrays
|
||||||
.asList(new Exprent[]{vevar.copy(), new ConstExprent(VarType.VARTYPE_INT, new Integer(Math.abs(instr.getOperand(1))))}))));
|
.asList(vevar.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null)),
|
||||||
|
bytecode_offsets), bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_i2l:
|
case opc_i2l:
|
||||||
case opc_i2f:
|
case opc_i2f:
|
||||||
@ -480,14 +436,14 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_i2b:
|
case opc_i2b:
|
||||||
case opc_i2c:
|
case opc_i2c:
|
||||||
case opc_i2s:
|
case opc_i2s:
|
||||||
pushEx(stack, exprlist, new FunctionExprent(func3[instr.opcode - opc_i2l], stack));
|
pushEx(stack, exprlist, new FunctionExprent(func3[instr.opcode - opc_i2l], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_lcmp:
|
case opc_lcmp:
|
||||||
case opc_fcmpl:
|
case opc_fcmpl:
|
||||||
case opc_fcmpg:
|
case opc_fcmpg:
|
||||||
case opc_dcmpl:
|
case opc_dcmpl:
|
||||||
case opc_dcmpg:
|
case opc_dcmpg:
|
||||||
pushEx(stack, exprlist, new FunctionExprent(func4[instr.opcode - opc_lcmp], stack));
|
pushEx(stack, exprlist, new FunctionExprent(func4[instr.opcode - opc_lcmp], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_ifeq:
|
case opc_ifeq:
|
||||||
case opc_ifne:
|
case opc_ifne:
|
||||||
@ -495,7 +451,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_ifge:
|
case opc_ifge:
|
||||||
case opc_ifgt:
|
case opc_ifgt:
|
||||||
case opc_ifle:
|
case opc_ifle:
|
||||||
exprlist.add(new IfExprent(negifs[func5[instr.opcode - opc_ifeq]], stack));
|
exprlist.add(new IfExprent(negIfs[func5[instr.opcode - opc_ifeq]], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_if_icmpeq:
|
case opc_if_icmpeq:
|
||||||
case opc_if_icmpne:
|
case opc_if_icmpne:
|
||||||
@ -505,15 +461,15 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_if_icmple:
|
case opc_if_icmple:
|
||||||
case opc_if_acmpeq:
|
case opc_if_acmpeq:
|
||||||
case opc_if_acmpne:
|
case opc_if_acmpne:
|
||||||
exprlist.add(new IfExprent(negifs[func6[instr.opcode - opc_if_icmpeq]], stack));
|
exprlist.add(new IfExprent(negIfs[func6[instr.opcode - opc_if_icmpeq]], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_ifnull:
|
case opc_ifnull:
|
||||||
case opc_ifnonnull:
|
case opc_ifnonnull:
|
||||||
exprlist.add(new IfExprent(negifs[func7[instr.opcode - opc_ifnull]], stack));
|
exprlist.add(new IfExprent(negIfs[func7[instr.opcode - opc_ifnull]], stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_tableswitch:
|
case opc_tableswitch:
|
||||||
case opc_lookupswitch:
|
case opc_lookupswitch:
|
||||||
exprlist.add(new SwitchExprent(stack.pop()));
|
exprlist.add(new SwitchExprent(stack.pop(), bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_ireturn:
|
case opc_ireturn:
|
||||||
case opc_lreturn:
|
case opc_lreturn:
|
||||||
@ -524,51 +480,47 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_athrow:
|
case opc_athrow:
|
||||||
exprlist.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
|
exprlist.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
|
||||||
instr.opcode == opc_return ? null : stack.pop(),
|
instr.opcode == opc_return ? null : stack.pop(),
|
||||||
instr.opcode == opc_athrow
|
instr.opcode == opc_athrow ? null : methodDescriptor.ret,
|
||||||
? null
|
bytecode_offsets));
|
||||||
: ((MethodDescriptor)DecompilerContext
|
|
||||||
.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret));
|
|
||||||
break;
|
break;
|
||||||
case opc_monitorenter:
|
case opc_monitorenter:
|
||||||
case opc_monitorexit:
|
case opc_monitorexit:
|
||||||
exprlist.add(new MonitorExprent(func8[instr.opcode - opc_monitorenter], stack.pop()));
|
exprlist.add(new MonitorExprent(func8[instr.opcode - opc_monitorenter], stack.pop(), bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_checkcast:
|
case opc_checkcast:
|
||||||
case opc_instanceof:
|
case opc_instanceof:
|
||||||
stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true), null));
|
stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true), null, null));
|
||||||
case opc_arraylength:
|
case opc_arraylength:
|
||||||
pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode).intValue(), stack));
|
pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode), stack, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_getstatic:
|
case opc_getstatic:
|
||||||
case opc_getfield:
|
case opc_getfield:
|
||||||
pushEx(stack, exprlist,
|
pushEx(stack, exprlist,
|
||||||
new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_getstatic ? null : stack.pop()));
|
new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == opc_getstatic ? null : stack.pop(),
|
||||||
|
bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_putstatic:
|
case opc_putstatic:
|
||||||
case opc_putfield:
|
case opc_putfield:
|
||||||
Exprent valfield = stack.pop();
|
Exprent valfield = stack.pop();
|
||||||
Exprent exprfield =
|
Exprent exprfield =
|
||||||
new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_putstatic ? null : stack.pop());
|
new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == opc_putstatic ? null : stack.pop(),
|
||||||
exprlist.add(new AssignmentExprent(exprfield, valfield));
|
bytecode_offsets);
|
||||||
|
exprlist.add(new AssignmentExprent(exprfield, valfield, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_invokevirtual:
|
case opc_invokevirtual:
|
||||||
case opc_invokespecial:
|
case opc_invokespecial:
|
||||||
case opc_invokestatic:
|
case opc_invokestatic:
|
||||||
case opc_invokeinterface:
|
case opc_invokeinterface:
|
||||||
case opc_invokedynamic:
|
case opc_invokedynamic:
|
||||||
if (instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
|
if (instr.opcode != opc_invokedynamic || instr.bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) {
|
||||||
|
LinkConstant invoke_constant = pool.getLinkConstant(instr.operand(0));
|
||||||
LinkConstant invoke_constant = pool.getLinkConstant(instr.getOperand(0));
|
|
||||||
int dynamic_invokation_type = -1;
|
|
||||||
|
|
||||||
|
List<PooledConstant> bootstrap_arguments = null;
|
||||||
if (instr.opcode == opc_invokedynamic && bootstrap != null) {
|
if (instr.opcode == opc_invokedynamic && bootstrap != null) {
|
||||||
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
|
bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
|
||||||
LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
|
|
||||||
|
|
||||||
dynamic_invokation_type = content_method_handle.index1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, stack, dynamic_invokation_type);
|
InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, bootstrap_arguments, stack, bytecode_offsets);
|
||||||
if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
|
if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
|
||||||
exprlist.add(exprinv);
|
exprlist.add(exprinv);
|
||||||
}
|
}
|
||||||
@ -580,15 +532,15 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_new:
|
case opc_new:
|
||||||
case opc_anewarray:
|
case opc_anewarray:
|
||||||
case opc_multianewarray:
|
case opc_multianewarray:
|
||||||
int arrdims = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.getOperand(1);
|
int dimensions = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.operand(1);
|
||||||
VarType arrtype = new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true);
|
VarType arrType = new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true);
|
||||||
if (instr.opcode != opc_multianewarray) {
|
if (instr.opcode != opc_multianewarray) {
|
||||||
arrtype.arraydim += arrdims;
|
arrType = arrType.resizeArrayDim(arrType.arrayDim + dimensions);
|
||||||
}
|
}
|
||||||
pushEx(stack, exprlist, new NewExprent(arrtype, stack, arrdims));
|
pushEx(stack, exprlist, new NewExprent(arrType, stack, dimensions, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_newarray:
|
case opc_newarray:
|
||||||
pushEx(stack, exprlist, new NewExprent(new VarType(arr_type[instr.getOperand(0) - 4], 1), stack, 1));
|
pushEx(stack, exprlist, new NewExprent(new VarType(arrTypeIds[instr.operand(0) - 4], 1), stack, 1, bytecode_offsets));
|
||||||
break;
|
break;
|
||||||
case opc_dup:
|
case opc_dup:
|
||||||
pushEx(stack, exprlist, stack.getByOffset(-1).copy());
|
pushEx(stack, exprlist, stack.getByOffset(-1).copy());
|
||||||
@ -597,7 +549,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||||
break;
|
break;
|
||||||
case opc_dup_x2:
|
case opc_dup_x2:
|
||||||
if (stack.getByOffset(-2).getExprType().stack_size == 2) {
|
if (stack.getByOffset(-2).getExprType().stackSize == 2) {
|
||||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -605,7 +557,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case opc_dup2:
|
case opc_dup2:
|
||||||
if (stack.getByOffset(-1).getExprType().stack_size == 2) {
|
if (stack.getByOffset(-1).getExprType().stackSize == 2) {
|
||||||
pushEx(stack, exprlist, stack.getByOffset(-1).copy());
|
pushEx(stack, exprlist, stack.getByOffset(-1).copy());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -614,7 +566,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case opc_dup2_x1:
|
case opc_dup2_x1:
|
||||||
if (stack.getByOffset(-1).getExprType().stack_size == 2) {
|
if (stack.getByOffset(-1).getExprType().stackSize == 2) {
|
||||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -623,8 +575,8 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case opc_dup2_x2:
|
case opc_dup2_x2:
|
||||||
if (stack.getByOffset(-1).getExprType().stack_size == 2) {
|
if (stack.getByOffset(-1).getExprType().stackSize == 2) {
|
||||||
if (stack.getByOffset(-2).getExprType().stack_size == 2) {
|
if (stack.getByOffset(-2).getExprType().stackSize == 2) {
|
||||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -632,7 +584,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (stack.getByOffset(-3).getExprType().stack_size == 2) {
|
if (stack.getByOffset(-3).getExprType().stackSize == 2) {
|
||||||
insertByOffsetEx(-3, stack, exprlist, -2);
|
insertByOffsetEx(-3, stack, exprlist, -2);
|
||||||
insertByOffsetEx(-3, stack, exprlist, -1);
|
insertByOffsetEx(-3, stack, exprlist, -1);
|
||||||
}
|
}
|
||||||
@ -647,12 +599,38 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
stack.pop();
|
stack.pop();
|
||||||
break;
|
break;
|
||||||
case opc_pop:
|
case opc_pop:
|
||||||
case opc_pop2:
|
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
break;
|
||||||
|
case opc_pop2:
|
||||||
|
if (stack.getByOffset(-1).getExprType().stackSize == 1) {
|
||||||
|
// Since value at the top of the stack is a value of category 1 (JVMS9 2.11.1)
|
||||||
|
// we should remove one more item from the stack.
|
||||||
|
// See JVMS9 pop2 chapter.
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
stack.pop();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int nextMeaningfulOffset(BasicBlock block, int index) {
|
||||||
|
InstructionSequence seq = block.getSeq();
|
||||||
|
while (++index < seq.length()) {
|
||||||
|
switch (seq.getInstr(index).opcode) {
|
||||||
|
case opc_nop:
|
||||||
|
case opc_istore:
|
||||||
|
case opc_lstore:
|
||||||
|
case opc_fstore:
|
||||||
|
case opc_dstore:
|
||||||
|
case opc_astore:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return block.getOldOffset(index);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
|
private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
|
||||||
pushEx(stack, exprlist, exprent, null);
|
pushEx(stack, exprlist, exprent, null);
|
||||||
}
|
}
|
||||||
@ -662,7 +640,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
VarExprent var = new VarExprent(varindex, vartype == null ? exprent.getExprType() : vartype, varProcessor);
|
VarExprent var = new VarExprent(varindex, vartype == null ? exprent.getExprType() : vartype, varProcessor);
|
||||||
var.setStack(true);
|
var.setStack(true);
|
||||||
|
|
||||||
exprlist.add(new AssignmentExprent(var, exprent));
|
exprlist.add(new AssignmentExprent(var, exprent, null));
|
||||||
stack.push(var.copy());
|
stack.push(var.copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,20 +648,20 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
|
|
||||||
int base = VarExprent.STACK_BASE + stack.size();
|
int base = VarExprent.STACK_BASE + stack.size();
|
||||||
|
|
||||||
LinkedList<VarExprent> lst = new LinkedList<VarExprent>();
|
LinkedList<VarExprent> lst = new LinkedList<>();
|
||||||
|
|
||||||
for (int i = -1; i >= offset; i--) {
|
for (int i = -1; i >= offset; i--) {
|
||||||
Exprent varex = stack.pop();
|
Exprent varex = stack.pop();
|
||||||
VarExprent varnew = new VarExprent(base + i + 1, varex.getExprType(), varProcessor);
|
VarExprent varnew = new VarExprent(base + i + 1, varex.getExprType(), varProcessor);
|
||||||
varnew.setStack(true);
|
varnew.setStack(true);
|
||||||
exprlist.add(new AssignmentExprent(varnew, varex));
|
exprlist.add(new AssignmentExprent(varnew, varex, null));
|
||||||
lst.add(0, (VarExprent)varnew.copy());
|
lst.add(0, (VarExprent)varnew.copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
Exprent exprent = lst.get(lst.size() + copyoffset).copy();
|
Exprent exprent = lst.get(lst.size() + copyoffset).copy();
|
||||||
VarExprent var = new VarExprent(base + offset, exprent.getExprType(), varProcessor);
|
VarExprent var = new VarExprent(base + offset, exprent.getExprType(), varProcessor);
|
||||||
var.setStack(true);
|
var.setStack(true);
|
||||||
exprlist.add(new AssignmentExprent(var, exprent));
|
exprlist.add(new AssignmentExprent(var, exprent, null));
|
||||||
lst.add(0, (VarExprent)var.copy());
|
lst.add(0, (VarExprent)var.copy());
|
||||||
|
|
||||||
for (VarExprent expr : lst) {
|
for (VarExprent expr : lst) {
|
||||||
@ -696,7 +674,6 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getTypeName(VarType type, boolean getShort) {
|
public static String getTypeName(VarType type, boolean getShort) {
|
||||||
|
|
||||||
int tp = type.type;
|
int tp = type.type;
|
||||||
if (tp <= CodeConstants.TYPE_BOOLEAN) {
|
if (tp <= CodeConstants.TYPE_BOOLEAN) {
|
||||||
return typeNames[tp];
|
return typeNames[tp];
|
||||||
@ -731,12 +708,9 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getCastTypeName(VarType type, boolean getShort) {
|
public static String getCastTypeName(VarType type, boolean getShort) {
|
||||||
String s = getTypeName(type, getShort);
|
StringBuilder s = new StringBuilder(getTypeName(type, getShort));
|
||||||
int dim = type.arraydim;
|
TextUtil.append(s, "[]", type.arrayDim);
|
||||||
while (dim-- > 0) {
|
return s.toString();
|
||||||
s += "[]";
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PrimitiveExprsList getExpressionData(VarExprent var) {
|
public static PrimitiveExprsList getExpressionData(VarExprent var) {
|
||||||
@ -744,61 +718,63 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
VarExprent vartmp = new VarExprent(VarExprent.STACK_BASE, var.getExprType(), var.getProcessor());
|
VarExprent vartmp = new VarExprent(VarExprent.STACK_BASE, var.getExprType(), var.getProcessor());
|
||||||
vartmp.setStack(true);
|
vartmp.setStack(true);
|
||||||
|
|
||||||
prlst.getLstExprents().add(new AssignmentExprent(vartmp, var.copy()));
|
prlst.getLstExprents().add(new AssignmentExprent(vartmp, var.copy(), null));
|
||||||
prlst.getStack().push(vartmp.copy());
|
prlst.getStack().push(vartmp.copy());
|
||||||
return prlst;
|
return prlst;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean endsWithSemikolon(Exprent expr) {
|
public static boolean endsWithSemicolon(Exprent expr) {
|
||||||
int type = expr.type;
|
int type = expr.type;
|
||||||
return !(type == Exprent.EXPRENT_SWITCH ||
|
return !(type == Exprent.EXPRENT_SWITCH ||
|
||||||
type == Exprent.EXPRENT_MONITOR ||
|
type == Exprent.EXPRENT_MONITOR ||
|
||||||
type == Exprent.EXPRENT_IF ||
|
type == Exprent.EXPRENT_IF ||
|
||||||
(type == Exprent.EXPRENT_VAR && ((VarExprent)expr)
|
(type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef()));
|
||||||
.isClassdef()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String jmpWrapper(Statement stat, int indent, boolean semicolon, BytecodeMappingTracer tracer) {
|
private static void addDeletedGotoInstructionMapping(Statement stat, BytecodeMappingTracer tracer) {
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
if (stat instanceof BasicBlockStatement) {
|
||||||
|
BasicBlock block = ((BasicBlockStatement)stat).getBlock();
|
||||||
|
List<Integer> offsets = block.getInstrOldOffsets();
|
||||||
|
if (!offsets.isEmpty() &&
|
||||||
|
offsets.size() > block.getSeq().length()) { // some instructions have been deleted, but we still have offsets
|
||||||
|
tracer.addMapping(offsets.get(offsets.size() - 1)); // add the last offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder();
|
public static TextBuffer jmpWrapper(Statement stat, int indent, boolean semicolon, BytecodeMappingTracer tracer) {
|
||||||
String content = stat.toJava(indent, tracer);
|
TextBuffer buf = stat.toJava(indent, tracer);
|
||||||
if (!(stat instanceof IfStatement) && !(stat instanceof DoStatement) && !(stat instanceof SequenceStatement)) {
|
|
||||||
content = Util.rtrim(content);
|
|
||||||
}
|
|
||||||
buf.append(content);
|
|
||||||
if (!(stat instanceof IfStatement) && !(stat instanceof DoStatement) && !(stat instanceof SequenceStatement) && buf.length() != 0) {
|
|
||||||
buf.append(new_line_separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
|
List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
|
||||||
if (lstSuccs.size() == 1) {
|
if (lstSuccs.size() == 1) {
|
||||||
StatEdge edge = lstSuccs.get(0);
|
StatEdge edge = lstSuccs.get(0);
|
||||||
if (edge.getType() != StatEdge.TYPE_REGULAR && edge.explicit && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
|
if (edge.getType() != StatEdge.TYPE_REGULAR && edge.explicit && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
|
||||||
buf.append(InterpreterUtil.getIndentString(indent));
|
buf.appendIndent(indent);
|
||||||
|
|
||||||
switch (edge.getType()) {
|
switch (edge.getType()) {
|
||||||
case StatEdge.TYPE_BREAK:
|
case StatEdge.TYPE_BREAK:
|
||||||
|
addDeletedGotoInstructionMapping(stat, tracer);
|
||||||
buf.append("break");
|
buf.append("break");
|
||||||
break;
|
break;
|
||||||
case StatEdge.TYPE_CONTINUE:
|
case StatEdge.TYPE_CONTINUE:
|
||||||
|
addDeletedGotoInstructionMapping(stat, tracer);
|
||||||
buf.append("continue");
|
buf.append("continue");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edge.labeled) {
|
if (edge.labeled) {
|
||||||
buf.append(" label").append(edge.closure.id);
|
buf.append(" label").append(edge.closure.id.toString());
|
||||||
}
|
}
|
||||||
buf.append(";").append(new_line_separator);
|
buf.append(";").appendLineSeparator();
|
||||||
tracer.incrementCurrentSourceLine();
|
tracer.incrementCurrentSourceLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf.length() == 0 && semicolon) {
|
if (buf.length() == 0 && semicolon) {
|
||||||
buf.append(InterpreterUtil.getIndentString(indent)).append(";").append(new_line_separator);
|
buf.appendIndent(indent).append(";").appendLineSeparator();
|
||||||
tracer.incrementCurrentSourceLine();
|
tracer.incrementCurrentSourceLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.toString();
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String buildJavaClassName(String name) {
|
public static String buildJavaClassName(String name) {
|
||||||
@ -815,92 +791,59 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String listToJava(List<Exprent> lst, int indent, BytecodeMappingTracer tracer) {
|
public static TextBuffer listToJava(List<? extends Exprent> lst, int indent, BytecodeMappingTracer tracer) {
|
||||||
if (lst == null || lst.isEmpty()) {
|
if (lst == null || lst.isEmpty()) {
|
||||||
return "";
|
return new TextBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
String indstr = InterpreterUtil.getIndentString(indent);
|
TextBuffer buf = new TextBuffer();
|
||||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
|
||||||
|
for (Exprent expr : lst) {
|
||||||
|
if (buf.length() > 0 && expr.type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef()) {
|
||||||
|
// separates local class definition from previous statements
|
||||||
|
buf.appendLineSeparator();
|
||||||
|
tracer.incrementCurrentSourceLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextBuffer content = expr.toJava(indent, tracer);
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
// Spigot Start
|
|
||||||
boolean inVar = false;
|
|
||||||
boolean bloodySpecialCaseForNewAssignments = false;
|
|
||||||
for (Iterator<Exprent> iter = SortUtil.sortIndexed(lst.iterator()); iter.hasNext();) {
|
|
||||||
Exprent expr = iter.next();
|
|
||||||
// Spigot End
|
|
||||||
String content = expr.toJava(indent, tracer);
|
|
||||||
if (content.length() > 0) {
|
if (content.length() > 0) {
|
||||||
|
if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent)expr).isClassDef()) {
|
||||||
if (expr instanceof VarExprent || expr instanceof AssignmentExprent) {
|
buf.appendIndent(indent);
|
||||||
inVar = true;
|
|
||||||
boolean wasASpecialLittleFlower = bloodySpecialCaseForNewAssignments;
|
|
||||||
bloodySpecialCaseForNewAssignments = expr instanceof VarExprent;
|
|
||||||
if (expr instanceof AssignmentExprent && ((AssignmentExprent) expr).getLeft() instanceof VarExprent) {
|
|
||||||
AssignmentExprent assignmentExprent = (AssignmentExprent) expr;
|
|
||||||
VarExprent var = (VarExprent) assignmentExprent.getLeft();
|
|
||||||
bloodySpecialCaseForNewAssignments = var.isDefinition();
|
|
||||||
}
|
|
||||||
if (wasASpecialLittleFlower && !bloodySpecialCaseForNewAssignments) {
|
|
||||||
buf.append(new_line_separator);
|
|
||||||
}
|
|
||||||
} else if (inVar) {
|
|
||||||
inVar = false;
|
|
||||||
if (!(expr instanceof InvocationExprent
|
|
||||||
|| expr instanceof ExitExprent
|
|
||||||
|| expr instanceof FunctionExprent
|
|
||||||
)
|
|
||||||
|| bloodySpecialCaseForNewAssignments) {
|
|
||||||
bloodySpecialCaseForNewAssignments = false;
|
|
||||||
buf.append(new_line_separator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent)expr).isClassdef()) {
|
|
||||||
buf.append(indstr);
|
|
||||||
}
|
}
|
||||||
buf.append(content);
|
buf.append(content);
|
||||||
if (expr.type == Exprent.EXPRENT_MONITOR && ((MonitorExprent)expr).getMontype() == MonitorExprent.MONITOR_ENTER) {
|
if (expr.type == Exprent.EXPRENT_MONITOR && ((MonitorExprent)expr).getMonType() == MonitorExprent.MONITOR_ENTER) {
|
||||||
buf.append("{}"); // empty synchronized block
|
buf.append("{}"); // empty synchronized block
|
||||||
}
|
}
|
||||||
if (endsWithSemikolon(expr)) {
|
if (endsWithSemicolon(expr)) {
|
||||||
buf.append(";");
|
buf.append(";");
|
||||||
}
|
}
|
||||||
buf.append(new_line_separator);
|
buf.appendLineSeparator();
|
||||||
|
|
||||||
tracer.incrementCurrentSourceLine();
|
tracer.incrementCurrentSourceLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.toString();
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConstExprent getDefaultArrayValue(VarType arrtype) {
|
public static ConstExprent getDefaultArrayValue(VarType arrType) {
|
||||||
|
ConstExprent defaultVal;
|
||||||
ConstExprent defaultval;
|
if (arrType.type == CodeConstants.TYPE_OBJECT || arrType.arrayDim > 0) {
|
||||||
if (arrtype.type == CodeConstants.TYPE_OBJECT || arrtype.arraydim > 0) {
|
defaultVal = new ConstExprent(VarType.VARTYPE_NULL, null, null);
|
||||||
defaultval = new ConstExprent(VarType.VARTYPE_NULL, null);
|
|
||||||
}
|
}
|
||||||
else if (arrtype.type == CodeConstants.TYPE_FLOAT) {
|
else if (arrType.type == CodeConstants.TYPE_FLOAT) {
|
||||||
defaultval = new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
|
defaultVal = new ConstExprent(VarType.VARTYPE_FLOAT, 0f, null);
|
||||||
}
|
}
|
||||||
else if (arrtype.type == CodeConstants.TYPE_LONG) {
|
else if (arrType.type == CodeConstants.TYPE_LONG) {
|
||||||
defaultval = new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
|
defaultVal = new ConstExprent(VarType.VARTYPE_LONG, 0L, null);
|
||||||
}
|
}
|
||||||
else if (arrtype.type == CodeConstants.TYPE_DOUBLE) {
|
else if (arrType.type == CodeConstants.TYPE_DOUBLE) {
|
||||||
defaultval = new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
|
defaultVal = new ConstExprent(VarType.VARTYPE_DOUBLE, 0d, null);
|
||||||
}
|
}
|
||||||
else { // integer types
|
else { // integer types
|
||||||
defaultval = new ConstExprent(0, true);
|
defaultVal = new ConstExprent(0, true, null);
|
||||||
}
|
}
|
||||||
|
return defaultVal;
|
||||||
return defaultval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getCastedExprent(Exprent exprent, VarType leftType, TextBuffer buffer, int indent,
|
|
||||||
boolean castNull, BytecodeMappingTracer tracer) {
|
|
||||||
return getCastedExprent(exprent, leftType, buffer, indent, castNull, false, tracer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean getCastedExprent(Exprent exprent,
|
public static boolean getCastedExprent(Exprent exprent,
|
||||||
@ -908,44 +851,89 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
TextBuffer buffer,
|
TextBuffer buffer,
|
||||||
int indent,
|
int indent,
|
||||||
boolean castNull,
|
boolean castNull,
|
||||||
boolean castAlways, BytecodeMappingTracer tracer) {
|
BytecodeMappingTracer tracer) {
|
||||||
|
return getCastedExprent(exprent, leftType, buffer, indent, castNull, false, false, false, tracer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getCastedExprent(Exprent exprent,
|
||||||
|
VarType leftType,
|
||||||
|
TextBuffer buffer,
|
||||||
|
int indent,
|
||||||
|
boolean castNull,
|
||||||
|
boolean castAlways,
|
||||||
|
boolean castNarrowing,
|
||||||
|
boolean unbox,
|
||||||
|
BytecodeMappingTracer tracer) {
|
||||||
|
|
||||||
|
if (unbox) {
|
||||||
|
// "unbox" invocation parameters, e.g. 'byteSet.add((byte)123)' or 'new ShortContainer((short)813)'
|
||||||
|
if (exprent.type == Exprent.EXPRENT_INVOCATION && ((InvocationExprent)exprent).isBoxingCall()) {
|
||||||
|
InvocationExprent invocationExprent = (InvocationExprent)exprent;
|
||||||
|
exprent = invocationExprent.getLstParameters().get(0);
|
||||||
|
int paramType = invocationExprent.getDescriptor().params[0].type;
|
||||||
|
if (exprent.type == Exprent.EXPRENT_CONST && ((ConstExprent)exprent).getConstType().type != paramType) {
|
||||||
|
leftType = new VarType(paramType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean ret = false;
|
|
||||||
VarType rightType = exprent.getExprType();
|
VarType rightType = exprent.getExprType();
|
||||||
|
|
||||||
String res = exprent.toJava(indent, tracer);
|
|
||||||
|
|
||||||
boolean cast =
|
boolean cast =
|
||||||
!leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT);
|
castAlways ||
|
||||||
cast |= castAlways && !leftType.equals(rightType); // Spigot
|
(!leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) ||
|
||||||
|
(castNull && rightType.type == CodeConstants.TYPE_NULL && !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType))) ||
|
||||||
|
(castNarrowing && isIntConstant(exprent) && isNarrowedIntType(leftType));
|
||||||
|
|
||||||
if (!cast && castNull && rightType.type == CodeConstants.TYPE_NULL) {
|
boolean quote = cast && exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST);
|
||||||
// check for a nameless anonymous class
|
|
||||||
cast = !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType));
|
|
||||||
}
|
|
||||||
if (!cast) {
|
|
||||||
cast = isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cast) {
|
// cast instead to 'byte' / 'short' when int constant is used as a value for 'Byte' / 'Short'
|
||||||
if (exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
|
if (castNarrowing && exprent.type == Exprent.EXPRENT_CONST && !((ConstExprent) exprent).isNull()) {
|
||||||
res = "(" + res + ")";
|
if (leftType.equals(VarType.VARTYPE_BYTE_OBJ)) {
|
||||||
|
leftType = VarType.VARTYPE_BYTE;
|
||||||
|
}
|
||||||
|
else if (leftType.equals(VarType.VARTYPE_SHORT_OBJ)) {
|
||||||
|
leftType = VarType.VARTYPE_SHORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = "(" + getCastTypeName(leftType) + ") " + res;
|
|
||||||
ret = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(res);
|
String name = getCastTypeName(leftType);
|
||||||
|
|
||||||
return ret;
|
if (exprent instanceof NewExprent)
|
||||||
|
{
|
||||||
|
if (((NewExprent) exprent).isVarArgParam())
|
||||||
|
{
|
||||||
|
quote = cast = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name.equals("Object"))
|
||||||
|
{
|
||||||
|
quote = cast = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((leftType.type == CodeConstants.TYPE_NULL))
|
||||||
|
{
|
||||||
|
quote = cast = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cast) buffer.append('(').append(name).append(')');
|
||||||
|
|
||||||
|
if (quote) buffer.append('(');
|
||||||
|
|
||||||
|
if (exprent.type == Exprent.EXPRENT_CONST) {
|
||||||
|
((ConstExprent) exprent).adjustConstType(leftType);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append(exprent.toJava(indent, tracer));
|
||||||
|
|
||||||
|
if (quote) buffer.append(')');
|
||||||
|
|
||||||
|
return cast;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isIntConstant(Exprent exprent) {
|
private static boolean isIntConstant(Exprent exprent) {
|
||||||
|
|
||||||
if (exprent.type == Exprent.EXPRENT_CONST) {
|
if (exprent.type == Exprent.EXPRENT_CONST) {
|
||||||
ConstExprent cexpr = (ConstExprent)exprent;
|
switch (((ConstExprent)exprent).getConstType().type) {
|
||||||
switch (cexpr.getConsttype().type) {
|
|
||||||
case CodeConstants.TYPE_BYTE:
|
case CodeConstants.TYPE_BYTE:
|
||||||
case CodeConstants.TYPE_BYTECHAR:
|
case CodeConstants.TYPE_BYTECHAR:
|
||||||
case CodeConstants.TYPE_SHORT:
|
case CodeConstants.TYPE_SHORT:
|
||||||
@ -957,4 +945,9 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static boolean isNarrowedIntType(VarType type) {
|
||||||
|
return VarType.VARTYPE_INT.isStrictSuperset(type) ||
|
||||||
|
type.equals(VarType.VARTYPE_BYTE_OBJ) || type.equals(VarType.VARTYPE_SHORT_OBJ);
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
@ -28,17 +14,13 @@ public class ExprentStack extends ListStack<Exprent> {
|
|||||||
pointer = list.getPointer();
|
pointer = list.getPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Exprent push(Exprent item) {
|
@Override
|
||||||
super.push(item);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Exprent pop() {
|
public Exprent pop() {
|
||||||
|
|
||||||
return this.remove(--pointer);
|
return this.remove(--pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ExprentStack clone() {
|
public ExprentStack clone() {
|
||||||
return new ExprentStack(this);
|
return new ExprentStack(this);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,10 @@
|
|||||||
/*
|
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.*;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
|
import org.jetbrains.java.decompiler.code.Instruction;
|
||||||
|
import org.jetbrains.java.decompiler.code.InstructionSequence;
|
||||||
|
import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
||||||
@ -36,8 +25,10 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
|
||||||
@ -45,30 +36,24 @@ import java.util.*;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public class FinallyProcessor {
|
public class FinallyProcessor {
|
||||||
|
private final Map<Integer, Integer> finallyBlockIDs = new HashMap<>();
|
||||||
|
private final Map<Integer, Integer> catchallBlockIDs = new HashMap<>();
|
||||||
|
|
||||||
private Map<Integer, Integer> finallyBlockIDs = new HashMap<Integer, Integer>();
|
private final MethodDescriptor methodDescriptor;
|
||||||
private Map<Integer, Integer> catchallBlockIDs = new HashMap<Integer, Integer>();
|
private final VarProcessor varProcessor;
|
||||||
|
|
||||||
private VarProcessor varprocessor;
|
public FinallyProcessor(MethodDescriptor md, VarProcessor varProc) {
|
||||||
|
methodDescriptor = md;
|
||||||
public FinallyProcessor(VarProcessor varprocessor) {
|
varProcessor = varProc;
|
||||||
this.varprocessor = varprocessor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean iterateGraph(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
|
public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, ControlFlowGraph graph) {
|
||||||
// return processStatement(mt, root, graph, root);
|
int bytecodeVersion = mt.getBytecodeVersion();
|
||||||
return processStatementEx(mt, root, graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
|
LinkedList<Statement> stack = new LinkedList<>();
|
||||||
|
|
||||||
int bytecode_version = mt.getClassStruct().getBytecodeVersion();
|
|
||||||
|
|
||||||
LinkedList<Statement> stack = new LinkedList<Statement>();
|
|
||||||
stack.add(root);
|
stack.add(root);
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
|
|
||||||
Statement stat = stack.removeLast();
|
Statement stat = stack.removeLast();
|
||||||
|
|
||||||
Statement parent = stat.getParent();
|
Statement parent = stat.getParent();
|
||||||
@ -83,30 +68,26 @@ public class FinallyProcessor {
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else if (finallyBlockIDs.containsKey(handler.id)) {
|
else if (finallyBlockIDs.containsKey(handler.id)) {
|
||||||
|
|
||||||
fin.setFinally(true);
|
fin.setFinally(true);
|
||||||
|
|
||||||
Integer var = finallyBlockIDs.get(handler.id);
|
Integer var = finallyBlockIDs.get(handler.id);
|
||||||
fin.setMonitor(var == null ? null : new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
|
fin.setMonitor(var == null ? null : new VarExprent(var, VarType.VARTYPE_INT, varProcessor));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Record inf = getFinallyInformation(cl, mt, root, fin);
|
||||||
Record inf = getFinallyInformation(mt, root, fin);
|
|
||||||
|
|
||||||
if (inf == null) { // inconsistent finally
|
if (inf == null) { // inconsistent finally
|
||||||
catchallBlockIDs.put(handler.id, null);
|
catchallBlockIDs.put(handler.id, null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
|
if (DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
|
||||||
finallyBlockIDs.put(handler.id, null);
|
finallyBlockIDs.put(handler.id, null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
int varIndex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
||||||
|
insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varIndex, inf, bytecodeVersion);
|
||||||
|
|
||||||
int varindex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
finallyBlockIDs.put(handler.id, varIndex);
|
||||||
insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
|
|
||||||
|
|
||||||
finallyBlockIDs.put(handler.id, varindex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
|
DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
|
||||||
@ -124,63 +105,7 @@ public class FinallyProcessor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class Record {
|
||||||
// private boolean processStatement(StructMethod mt, RootStatement root, ControlFlowGraph graph, Statement stat) {
|
|
||||||
//
|
|
||||||
// boolean res = false;
|
|
||||||
//
|
|
||||||
// for(int i=stat.getStats().size()-1;i>=0;i--) {
|
|
||||||
// if(processStatement(mt, root, graph, stat.getStats().get(i))) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if(stat.type == Statement.TYPE_CATCHALL && !stat.isCopied()) {
|
|
||||||
//
|
|
||||||
// CatchAllStatement fin = (CatchAllStatement)stat;
|
|
||||||
// BasicBlock head = fin.getBasichead().getBlock();
|
|
||||||
// BasicBlock handler = fin.getHandler().getBasichead().getBlock();
|
|
||||||
//
|
|
||||||
// if(catchallBlockIDs.containsKey(handler.id)) {
|
|
||||||
// ; // do nothing
|
|
||||||
// }else if(finallyBlockIDs.containsKey(handler.id)) {
|
|
||||||
//
|
|
||||||
// fin.setFinally(true);
|
|
||||||
//
|
|
||||||
// Integer var = finallyBlockIDs.get(handler.id);
|
|
||||||
// fin.setMonitor(var==null?null:new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// Object[] inf = getFinallyInformation(mt, root, fin);
|
|
||||||
//
|
|
||||||
// if(inf == null) { // inconsistent finally
|
|
||||||
// catchallBlockIDs.put(handler.id, null);
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// if(DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
|
|
||||||
// finallyBlockIDs.put(handler.id, null);
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
|
||||||
// insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf);
|
|
||||||
//
|
|
||||||
// finallyBlockIDs.put(handler.id, varindex);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// DeadCodeHelper.removeEmptyBlocks(graph);
|
|
||||||
// DeadCodeHelper.mergeBasicBlocks(graph);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// res = true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return res;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static class Record {
|
|
||||||
private final int firstCode;
|
private final int firstCode;
|
||||||
private final Map<BasicBlock, Boolean> mapLast;
|
private final Map<BasicBlock, Boolean> mapLast;
|
||||||
|
|
||||||
@ -190,10 +115,8 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) {
|
||||||
private static Record getFinallyInformation(StructMethod mt, RootStatement root, CatchAllStatement fstat) {
|
Map<BasicBlock, Boolean> mapLast = new HashMap<>();
|
||||||
|
|
||||||
Map<BasicBlock, Boolean> mapLast = new HashMap<BasicBlock, Boolean>();
|
|
||||||
|
|
||||||
BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
|
BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
|
||||||
BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
|
BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
|
||||||
@ -209,26 +132,25 @@ public class FinallyProcessor {
|
|||||||
firstcode = 2;
|
firstcode = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprProcessor proc = new ExprProcessor();
|
ExprProcessor proc = new ExprProcessor(methodDescriptor, varProcessor);
|
||||||
proc.processStatement(root, mt.getClassStruct());
|
proc.processStatement(root, cl);
|
||||||
|
|
||||||
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
|
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
|
||||||
ssa.splitVariables(root, mt);
|
ssa.splitVariables(root, mt);
|
||||||
|
|
||||||
List<Exprent> lstExprents = firstBlockStatement.getExprents();
|
List<Exprent> lstExprents = firstBlockStatement.getExprents();
|
||||||
|
|
||||||
VarVersionPaar varpaar = new VarVersionPaar((VarExprent)((AssignmentExprent)lstExprents.get(firstcode == 2 ? 1 : 0)).getLeft());
|
VarVersionPair varpaar = new VarVersionPair((VarExprent)((AssignmentExprent)lstExprents.get(firstcode == 2 ? 1 : 0)).getLeft());
|
||||||
|
|
||||||
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
||||||
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
||||||
|
|
||||||
LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
|
LinkedList<DirectNode> stack = new LinkedList<>();
|
||||||
stack.add(dgraph.first);
|
stack.add(dgraph.first);
|
||||||
|
|
||||||
Set<DirectNode> setVisited = new HashSet<DirectNode>();
|
Set<DirectNode> setVisited = new HashSet<>();
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
|
|
||||||
DirectNode node = stack.removeFirst();
|
DirectNode node = stack.removeFirst();
|
||||||
|
|
||||||
if (setVisited.contains(node)) {
|
if (setVisited.contains(node)) {
|
||||||
@ -259,7 +181,7 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (Exprent expr : lst) {
|
for (Exprent expr : lst) {
|
||||||
if (expr.type == Exprent.EXPRENT_VAR && new VarVersionPaar((VarExprent)expr).equals(varpaar)) {
|
if (expr.type == Exprent.EXPRENT_VAR && new VarVersionPair((VarExprent)expr).equals(varpaar)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -269,7 +191,7 @@ public class FinallyProcessor {
|
|||||||
found = false;
|
found = false;
|
||||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent exexpr = (ExitExprent)exprent;
|
ExitExprent exexpr = (ExitExprent)exprent;
|
||||||
if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR) {
|
if (exexpr.getExitType() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +209,7 @@ public class FinallyProcessor {
|
|||||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||||
AssignmentExprent assexpr = (AssignmentExprent)exprent;
|
AssignmentExprent assexpr = (AssignmentExprent)exprent;
|
||||||
if (assexpr.getRight().type == Exprent.EXPRENT_VAR &&
|
if (assexpr.getRight().type == Exprent.EXPRENT_VAR &&
|
||||||
new VarVersionPaar((VarExprent)assexpr.getRight()).equals(varpaar)) {
|
new VarVersionPair((VarExprent)assexpr.getRight()).equals(varpaar)) {
|
||||||
|
|
||||||
Exprent next = null;
|
Exprent next = null;
|
||||||
if (i == node.exprents.size() - 1) {
|
if (i == node.exprents.size() - 1) {
|
||||||
@ -305,7 +227,7 @@ public class FinallyProcessor {
|
|||||||
boolean found = false;
|
boolean found = false;
|
||||||
if (next != null && next.type == Exprent.EXPRENT_EXIT) {
|
if (next != null && next.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent exexpr = (ExitExprent)next;
|
ExitExprent exexpr = (ExitExprent)next;
|
||||||
if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR
|
if (exexpr.getExitType() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR
|
||||||
&& assexpr.getLeft().equals(exexpr.getValue())) {
|
&& assexpr.getLeft().equals(exexpr.getValue())) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@ -375,8 +297,7 @@ public class FinallyProcessor {
|
|||||||
int var,
|
int var,
|
||||||
Record information,
|
Record information,
|
||||||
int bytecode_version) {
|
int bytecode_version) {
|
||||||
|
Set<BasicBlock> setCopy = new HashSet<>(setTry);
|
||||||
Set<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry);
|
|
||||||
|
|
||||||
int finallytype = information.firstCode;
|
int finallytype = information.firstCode;
|
||||||
Map<BasicBlock, Boolean> mapLast = information.mapLast;
|
Map<BasicBlock, Boolean> mapLast = information.mapLast;
|
||||||
@ -394,21 +315,15 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
// disable semaphore at statement exit points
|
// disable semaphore at statement exit points
|
||||||
for (BasicBlock block : setTry) {
|
for (BasicBlock block : setTry) {
|
||||||
|
|
||||||
List<BasicBlock> lstSucc = block.getSuccs();
|
List<BasicBlock> lstSucc = block.getSuccs();
|
||||||
for (BasicBlock dest : lstSucc) {
|
|
||||||
|
|
||||||
|
for (BasicBlock dest : lstSucc) {
|
||||||
// break out
|
// break out
|
||||||
if (!setCopy.contains(dest) && dest != graph.getLast()) {
|
if (dest != graph.getLast() && !setCopy.contains(dest)) {
|
||||||
// disable semaphore
|
// disable semaphore
|
||||||
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||||
|
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1);
|
||||||
seq.addInstruction(ConstantsUtil
|
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}), -1);
|
||||||
.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
|
// build a separate block
|
||||||
BasicBlock newblock = new BasicBlock(++graph.last_id);
|
BasicBlock newblock = new BasicBlock(++graph.last_id);
|
||||||
@ -435,14 +350,10 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable semaphor at the statement entrance
|
// enable semaphore at the statement entrance
|
||||||
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||||
seq.addInstruction(
|
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}), -1);
|
||||||
ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}),
|
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}), -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);
|
BasicBlock newhead = new BasicBlock(++graph.last_id);
|
||||||
newhead.setSeq(seq);
|
newhead.setSeq(seq);
|
||||||
@ -451,12 +362,8 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
// initialize semaphor with false
|
// initialize semaphor with false
|
||||||
seq = new SimpleInstructionSequence();
|
seq = new SimpleInstructionSequence();
|
||||||
seq.addInstruction(
|
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1);
|
||||||
ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}),
|
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}), -1);
|
||||||
-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);
|
||||||
@ -466,7 +373,7 @@ public class FinallyProcessor {
|
|||||||
setCopy.add(newhead);
|
setCopy.add(newhead);
|
||||||
setCopy.add(newheadinit);
|
setCopy.add(newheadinit);
|
||||||
|
|
||||||
for (BasicBlock hd : new HashSet<BasicBlock>(newheadinit.getSuccExceptions())) {
|
for (BasicBlock hd : new HashSet<>(newheadinit.getSuccExceptions())) {
|
||||||
ExceptionRangeCFG range = graph.getExceptionRange(hd, newheadinit);
|
ExceptionRangeCFG range = graph.getExceptionRange(hd, newheadinit);
|
||||||
|
|
||||||
if (setCopy.containsAll(range.getProtectedRange())) {
|
if (setCopy.containsAll(range.getProtectedRange())) {
|
||||||
@ -476,10 +383,8 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) {
|
private static void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) {
|
||||||
|
List<BasicBlock> lstTemp = new ArrayList<>();
|
||||||
List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
|
|
||||||
lstTemp.addAll(oldblock.getPreds());
|
lstTemp.addAll(oldblock.getPreds());
|
||||||
lstTemp.addAll(oldblock.getPredExceptions());
|
lstTemp.addAll(oldblock.getPredExceptions());
|
||||||
|
|
||||||
@ -510,9 +415,8 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<BasicBlock> getAllBasicBlocks(Statement stat) {
|
private static Set<BasicBlock> getAllBasicBlocks(Statement stat) {
|
||||||
|
List<Statement> lst = new LinkedList<>();
|
||||||
List<Statement> lst = new LinkedList<Statement>();
|
|
||||||
lst.add(stat);
|
lst.add(stat);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@ -529,7 +433,7 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
while (index < lst.size());
|
while (index < lst.size());
|
||||||
|
|
||||||
HashSet<BasicBlock> res = new LinkedHashSet<BasicBlock>(); // Spigot: Fix determinism
|
Set<BasicBlock> res = new HashSet<>();
|
||||||
|
|
||||||
for (Statement st : lst) {
|
for (Statement st : lst) {
|
||||||
res.add(((BasicBlockStatement)st).getBlock());
|
res.add(((BasicBlockStatement)st).getBlock());
|
||||||
@ -538,11 +442,9 @@ public class FinallyProcessor {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Record information) {
|
private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Record information) {
|
||||||
|
Set<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
|
||||||
HashSet<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
|
Set<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
|
||||||
HashSet<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
|
|
||||||
|
|
||||||
int finallytype = information.firstCode;
|
int finallytype = information.firstCode;
|
||||||
Map<BasicBlock, Boolean> mapLast = information.mapLast;
|
Map<BasicBlock, Boolean> mapLast = information.mapLast;
|
||||||
@ -571,7 +473,7 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// identify start blocks
|
// identify start blocks
|
||||||
HashSet<BasicBlock> startBlocks = new LinkedHashSet<BasicBlock>(); // Spigot: Fix determinism
|
Set<BasicBlock> startBlocks = new HashSet<>();
|
||||||
for (BasicBlock block : tryBlocks) {
|
for (BasicBlock block : tryBlocks) {
|
||||||
startBlocks.addAll(block.getSuccs());
|
startBlocks.addAll(block.getSuccs());
|
||||||
}
|
}
|
||||||
@ -580,7 +482,7 @@ public class FinallyProcessor {
|
|||||||
startBlocks.remove(graph.getLast());
|
startBlocks.remove(graph.getLast());
|
||||||
startBlocks.removeAll(tryBlocks);
|
startBlocks.removeAll(tryBlocks);
|
||||||
|
|
||||||
List<Area> lstAreas = new ArrayList<Area>();
|
List<Area> lstAreas = new ArrayList<>();
|
||||||
|
|
||||||
for (BasicBlock start : startBlocks) {
|
for (BasicBlock start : startBlocks) {
|
||||||
|
|
||||||
@ -620,7 +522,7 @@ public class FinallyProcessor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Area {
|
private static final class Area {
|
||||||
private final BasicBlock start;
|
private final BasicBlock start;
|
||||||
private final Set<BasicBlock> sample;
|
private final Set<BasicBlock> sample;
|
||||||
private final BasicBlock next;
|
private final BasicBlock next;
|
||||||
@ -634,33 +536,32 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
private Area compareSubgraphsEx(ControlFlowGraph graph,
|
private Area compareSubgraphsEx(ControlFlowGraph graph,
|
||||||
BasicBlock startSample,
|
BasicBlock startSample,
|
||||||
HashSet<BasicBlock> catchBlocks,
|
Set<BasicBlock> catchBlocks,
|
||||||
BasicBlock startCatch,
|
BasicBlock startCatch,
|
||||||
int finallytype,
|
int finallytype,
|
||||||
Map<BasicBlock, Boolean> mapLast,
|
Map<BasicBlock, Boolean> mapLast,
|
||||||
boolean skippedFirst) {
|
boolean skippedFirst) {
|
||||||
|
|
||||||
class BlockStackEntry {
|
class BlockStackEntry {
|
||||||
public BasicBlock blockCatch;
|
public final BasicBlock blockCatch;
|
||||||
public BasicBlock blockSample;
|
public final BasicBlock blockSample;
|
||||||
|
|
||||||
// TODO: correct handling (merging) of multiple paths
|
// TODO: correct handling (merging) of multiple paths
|
||||||
public List<int[]> lstStoreVars;
|
public final List<int[]> lstStoreVars;
|
||||||
|
|
||||||
public BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List<int[]> lstStoreVars) {
|
BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List<int[]> lstStoreVars) {
|
||||||
this.blockCatch = blockCatch;
|
this.blockCatch = blockCatch;
|
||||||
this.blockSample = blockSample;
|
this.blockSample = blockSample;
|
||||||
this.lstStoreVars = new ArrayList<int[]>(lstStoreVars);
|
this.lstStoreVars = new ArrayList<>(lstStoreVars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BlockStackEntry> stack = new LinkedList<BlockStackEntry>();
|
List<BlockStackEntry> stack = new LinkedList<>();
|
||||||
|
|
||||||
Set<BasicBlock> setSample = new HashSet<BasicBlock>();
|
Set<BasicBlock> setSample = new HashSet<>();
|
||||||
|
|
||||||
Map<String, BasicBlock[]> mapNext = new HashMap<String, BasicBlock[]>();
|
Map<String, BasicBlock[]> mapNext = new HashMap<>();
|
||||||
|
|
||||||
stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<int[]>()));
|
stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<>()));
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
|
|
||||||
@ -693,7 +594,6 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// exception successors
|
// exception successors
|
||||||
if (isLastBlock && blockSample.getSeq().isEmpty()) {
|
if (isLastBlock && blockSample.getSeq().isEmpty()) {
|
||||||
// do nothing, blockSample will be removed anyway
|
// do nothing, blockSample will be removed anyway
|
||||||
@ -721,8 +621,8 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
if (instrCatch.opcode == CodeConstants.opc_astore &&
|
if (instrCatch.opcode == CodeConstants.opc_astore &&
|
||||||
instrSample.opcode == CodeConstants.opc_astore) {
|
instrSample.opcode == CodeConstants.opc_astore) {
|
||||||
lst = new ArrayList<int[]>(lst);
|
lst = new ArrayList<>(lst);
|
||||||
lst.add(new int[]{instrCatch.getOperand(0), instrSample.getOperand(0)});
|
lst.add(new int[]{instrCatch.operand(0), instrSample.operand(0)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,7 +640,7 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isLastBlock) {
|
if (isLastBlock) {
|
||||||
Set<BasicBlock> setSuccs = new HashSet<BasicBlock>(blockSample.getSuccs());
|
Set<BasicBlock> setSuccs = new HashSet<>(blockSample.getSuccs());
|
||||||
setSuccs.removeAll(setSample);
|
setSuccs.removeAll(setSample);
|
||||||
|
|
||||||
for (BlockStackEntry stackent : stack) {
|
for (BlockStackEntry stackent : stack) {
|
||||||
@ -755,11 +655,10 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Area(startSample, setSample, getUniqueNext(graph, new HashSet<BasicBlock[]>(mapNext.values())));
|
return new Area(startSample, setSample, getUniqueNext(graph, new HashSet<>(mapNext.values())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BasicBlock getUniqueNext(ControlFlowGraph graph, Set<BasicBlock[]> setNext) {
|
private static BasicBlock getUniqueNext(ControlFlowGraph graph, Set<BasicBlock[]> setNext) {
|
||||||
|
|
||||||
// precondition: there is at most one true exit path in a finally statement
|
// precondition: there is at most one true exit path in a finally statement
|
||||||
|
|
||||||
BasicBlock next = null;
|
BasicBlock next = null;
|
||||||
@ -800,13 +699,11 @@ public class FinallyProcessor {
|
|||||||
Instruction instrNext = seqNext.getInstr(i);
|
Instruction instrNext = seqNext.getInstr(i);
|
||||||
Instruction instrBlock = seqBlock.getInstr(i);
|
Instruction instrBlock = seqBlock.getInstr(i);
|
||||||
|
|
||||||
if (instrNext.opcode != instrBlock.opcode || instrNext.wide != instrBlock.wide
|
if (!Instruction.equals(instrNext, instrBlock)) {
|
||||||
|| instrNext.operandsCount() != instrBlock.operandsCount()) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
for (int j = 0; j < instrNext.operandsCount(); j++) {
|
||||||
for (int j = 0; j < instrNext.getOperands().length; j++) {
|
if (instrNext.operand(j) != instrBlock.operand(j)) {
|
||||||
if (instrNext.getOperand(j) != instrBlock.getOperand(j)) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -848,7 +745,6 @@ public class FinallyProcessor {
|
|||||||
int type,
|
int type,
|
||||||
int finallytype,
|
int finallytype,
|
||||||
List<int[]> lstStoreVars) {
|
List<int[]> lstStoreVars) {
|
||||||
|
|
||||||
InstructionSequence seqPattern = pattern.getSeq();
|
InstructionSequence seqPattern = pattern.getSeq();
|
||||||
InstructionSequence seqSample = sample.getSeq();
|
InstructionSequence seqSample = sample.getSeq();
|
||||||
|
|
||||||
@ -863,11 +759,11 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
if ((type & 2) > 0) { // last
|
if ((type & 2) > 0) { // last
|
||||||
if (finallytype == 0 || finallytype == 2) {
|
if (finallytype == 0 || finallytype == 2) {
|
||||||
seqPattern.removeInstruction(seqPattern.length() - 1);
|
seqPattern.removeLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finallytype == 2) {
|
if (finallytype == 2) {
|
||||||
seqPattern.removeInstruction(seqPattern.length() - 1);
|
seqPattern.removeLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -887,18 +783,19 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (seqPattern.length() < seqSample.length()) { // split in two blocks
|
if (seqPattern.length() < seqSample.length()) { // split in two blocks
|
||||||
|
|
||||||
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||||
|
LinkedList<Integer> oldOffsets = new LinkedList<>();
|
||||||
for (int i = seqSample.length() - 1; i >= seqPattern.length(); i--) {
|
for (int i = seqSample.length() - 1; i >= seqPattern.length(); i--) {
|
||||||
seq.addInstruction(0, seqSample.getInstr(i), -1);
|
seq.addInstruction(0, seqSample.getInstr(i), -1);
|
||||||
|
oldOffsets.addFirst(sample.getOldOffset(i));
|
||||||
seqSample.removeInstruction(i);
|
seqSample.removeInstruction(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock newblock = new BasicBlock(++graph.last_id);
|
BasicBlock newblock = new BasicBlock(++graph.last_id);
|
||||||
newblock.setSeq(seq);
|
newblock.setSeq(seq);
|
||||||
|
newblock.getInstrOldOffsets().addAll(oldOffsets);
|
||||||
|
|
||||||
List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
|
List<BasicBlock> lstTemp = new ArrayList<>(sample.getSuccs());
|
||||||
lstTemp.addAll(sample.getSuccs());
|
|
||||||
|
|
||||||
// move successors
|
// move successors
|
||||||
for (BasicBlock suc : lstTemp) {
|
for (BasicBlock suc : lstTemp) {
|
||||||
@ -930,19 +827,15 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean equalInstructions(Instruction first, Instruction second, List<int[]> lstStoreVars) {
|
public boolean equalInstructions(Instruction first, Instruction second, List<int[]> lstStoreVars) {
|
||||||
if (first.opcode != second.opcode || first.wide != second.wide
|
if (!Instruction.equals(first, second)) {
|
||||||
|| first.operandsCount() != second.operandsCount()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first.group != CodeConstants.GROUP_JUMP && first.getOperands() != null) { // FIXME: switch comparison
|
if (first.group != CodeConstants.GROUP_JUMP) { // FIXME: switch comparison
|
||||||
for (int i = 0; i < first.getOperands().length; i++) {
|
for (int i = 0; i < first.operandsCount(); i++) {
|
||||||
|
int firstOp = first.operand(i);
|
||||||
int firstOp = first.getOperand(i);
|
int secondOp = second.operand(i);
|
||||||
int secondOp = second.getOperand(i);
|
|
||||||
|
|
||||||
if (firstOp != secondOp) {
|
if (firstOp != secondOp) {
|
||||||
|
|
||||||
// a-load/store instructions
|
// a-load/store instructions
|
||||||
if (first.opcode == CodeConstants.opc_aload || first.opcode == CodeConstants.opc_astore) {
|
if (first.opcode == CodeConstants.opc_aload || first.opcode == CodeConstants.opc_astore) {
|
||||||
for (int[] arr : lstStoreVars) {
|
for (int[] arr : lstStoreVars) {
|
||||||
@ -961,7 +854,6 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void deleteArea(ControlFlowGraph graph, Area area) {
|
private static void deleteArea(ControlFlowGraph graph, Area area) {
|
||||||
|
|
||||||
BasicBlock start = area.start;
|
BasicBlock start = area.start;
|
||||||
BasicBlock next = area.next;
|
BasicBlock next = area.next;
|
||||||
|
|
||||||
@ -975,14 +867,14 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// collect common exception ranges of predecessors and successors
|
// collect common exception ranges of predecessors and successors
|
||||||
Set<BasicBlock> setCommonExceptionHandlers = new HashSet<BasicBlock>(next.getSuccExceptions());
|
Set<BasicBlock> setCommonExceptionHandlers = new HashSet<>(next.getSuccExceptions());
|
||||||
for (BasicBlock pred : start.getPreds()) {
|
for (BasicBlock pred : start.getPreds()) {
|
||||||
setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
|
setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean is_outside_range = false;
|
boolean is_outside_range = false;
|
||||||
|
|
||||||
Set<BasicBlock> setPredecessors = new HashSet<BasicBlock>(start.getPreds());
|
Set<BasicBlock> setPredecessors = new HashSet<>(start.getPreds());
|
||||||
|
|
||||||
// replace start with next
|
// replace start with next
|
||||||
for (BasicBlock pred : setPredecessors) {
|
for (BasicBlock pred : setPredecessors) {
|
||||||
@ -1004,7 +896,7 @@ public class FinallyProcessor {
|
|||||||
is_outside_range = true;
|
is_outside_range = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
|
Set<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<>();
|
||||||
for (BasicBlock handler : block.getSuccExceptions()) {
|
for (BasicBlock handler : block.getSuccExceptions()) {
|
||||||
setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
|
setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
|
||||||
}
|
}
|
||||||
@ -1019,7 +911,7 @@ public class FinallyProcessor {
|
|||||||
// 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);
|
||||||
for (BasicBlock pred : new ArrayList<BasicBlock>(block.getPreds())) {
|
for (BasicBlock pred : new ArrayList<>(block.getPreds())) {
|
||||||
if (!setBlocks.contains(pred)) {
|
if (!setBlocks.contains(pred)) {
|
||||||
pred.replaceSuccessor(block, succs);
|
pred.replaceSuccessor(block, succs);
|
||||||
}
|
}
|
||||||
@ -1035,18 +927,15 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_outside_range) {
|
if (is_outside_range) {
|
||||||
|
|
||||||
// new empty block
|
// new empty block
|
||||||
BasicBlock emptyblock = new BasicBlock(++graph.last_id);
|
BasicBlock emptyblock = new BasicBlock(++graph.last_id);
|
||||||
emptyblock.setSeq(new SimpleInstructionSequence());
|
|
||||||
graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
|
graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
|
||||||
|
|
||||||
// add to ranges if necessary
|
// add to ranges if necessary
|
||||||
if (setCommonRemovedExceptionRanges != null) {
|
for (ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
|
||||||
for (ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
|
emptyblock.addSuccessorException(range.getHandler());
|
||||||
emptyblock.addSuccessorException(range.getHandler());
|
range.getProtectedRange().add(emptyblock);
|
||||||
range.getProtectedRange().add(emptyblock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert between predecessors and next
|
// insert between predecessors and next
|
||||||
@ -1058,7 +947,6 @@ public class FinallyProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) {
|
private static void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) {
|
||||||
|
|
||||||
InstructionSequence seq = block.getSeq();
|
InstructionSequence seq = block.getSeq();
|
||||||
|
|
||||||
if (finallytype == 3) { // empty finally handler
|
if (finallytype == 3) { // empty finally handler
|
||||||
@ -1075,11 +963,11 @@ public class FinallyProcessor {
|
|||||||
|
|
||||||
if ((blocktype & 2) > 0) { // last
|
if ((blocktype & 2) > 0) { // last
|
||||||
if (finallytype == 2 || finallytype == 0) {
|
if (finallytype == 2 || finallytype == 0) {
|
||||||
seq.removeInstruction(seq.length() - 1);
|
seq.removeLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finallytype == 2) { // astore
|
if (finallytype == 2) { // astore
|
||||||
seq.removeInstruction(seq.length() - 1);
|
seq.removeLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||||
@ -25,11 +11,10 @@ import org.jetbrains.java.decompiler.struct.attr.StructAnnotationAttribute;
|
|||||||
import org.jetbrains.java.decompiler.struct.attr.StructAnnotationParameterAttribute;
|
import org.jetbrains.java.decompiler.struct.attr.StructAnnotationParameterAttribute;
|
||||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class IdeaNotNullHelper {
|
public final class IdeaNotNullHelper {
|
||||||
|
|
||||||
|
|
||||||
public static boolean removeHardcodedChecks(Statement root, StructMethod mt) {
|
public static boolean removeHardcodedChecks(Statement root, StructMethod mt) {
|
||||||
@ -68,7 +53,7 @@ public class IdeaNotNullHelper {
|
|||||||
// TODO: FUNCTION_NE also possible if reversed order (in theory)
|
// TODO: FUNCTION_NE also possible if reversed order (in theory)
|
||||||
if (ifbranch != null &&
|
if (ifbranch != null &&
|
||||||
if_condition.type == Exprent.EXPRENT_FUNCTION &&
|
if_condition.type == Exprent.EXPRENT_FUNCTION &&
|
||||||
((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ &&
|
((FunctionExprent)if_condition).getFuncType() == FunctionExprent.FUNCTION_EQ &&
|
||||||
ifbranch.type == Statement.TYPE_BASICBLOCK &&
|
ifbranch.type == Statement.TYPE_BASICBLOCK &&
|
||||||
ifbranch.getExprents().size() == 1 &&
|
ifbranch.getExprents().size() == 1 &&
|
||||||
ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
|
ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
|
||||||
@ -85,11 +70,10 @@ public class IdeaNotNullHelper {
|
|||||||
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
||||||
|
|
||||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
||||||
VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
|
|
||||||
|
|
||||||
// parameter annotations
|
// parameter annotations
|
||||||
StructAnnotationParameterAttribute param_annotations = (StructAnnotationParameterAttribute)attributes
|
StructAnnotationParameterAttribute param_annotations =
|
||||||
.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
|
mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
|
||||||
if (param_annotations != null) {
|
if (param_annotations != null) {
|
||||||
|
|
||||||
List<List<AnnotationExprent>> param_annotations_lists = param_annotations.getParamAnnotations();
|
List<List<AnnotationExprent>> param_annotations_lists = param_annotations.getParamAnnotations();
|
||||||
@ -107,8 +91,9 @@ public class IdeaNotNullHelper {
|
|||||||
List<AnnotationExprent> annotations = param_annotations_lists.get(i - shift);
|
List<AnnotationExprent> annotations = param_annotations_lists.get(i - shift);
|
||||||
|
|
||||||
for (AnnotationExprent ann : annotations) {
|
for (AnnotationExprent ann : annotations) {
|
||||||
if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
|
if (ann.getClassName().equals("org/jetbrains/annotations/NotNull")) {
|
||||||
is_notnull_check = true;
|
is_notnull_check = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +101,7 @@ public class IdeaNotNullHelper {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
index += md.params[i].stack_size;
|
index += md.params[i].stackSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +112,7 @@ public class IdeaNotNullHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeParameterCheck(stat, mt);
|
removeParameterCheck(stat);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -135,7 +120,7 @@ public class IdeaNotNullHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void removeParameterCheck(Statement stat, StructMethod mt) {
|
private static void removeParameterCheck(Statement stat) {
|
||||||
|
|
||||||
Statement st = stat.getFirst();
|
Statement st = stat.getFirst();
|
||||||
while (st.type == Statement.TYPE_SEQUENCE) {
|
while (st.type == Statement.TYPE_SEQUENCE) {
|
||||||
@ -144,11 +129,7 @@ public class IdeaNotNullHelper {
|
|||||||
|
|
||||||
IfStatement ifstat = (IfStatement)st;
|
IfStatement ifstat = (IfStatement)st;
|
||||||
|
|
||||||
if (ifstat.getElsestat() == null) { // if
|
if (ifstat.getElsestat() != null) { // if - else
|
||||||
// TODO:
|
|
||||||
}
|
|
||||||
else { // if - else
|
|
||||||
|
|
||||||
StatEdge ifedge = ifstat.getIfEdge();
|
StatEdge ifedge = ifstat.getIfEdge();
|
||||||
StatEdge elseedge = ifstat.getElseEdge();
|
StatEdge elseedge = ifstat.getElseEdge();
|
||||||
|
|
||||||
@ -172,28 +153,22 @@ public class IdeaNotNullHelper {
|
|||||||
|
|
||||||
private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) {
|
private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) {
|
||||||
|
|
||||||
VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
|
|
||||||
|
|
||||||
boolean is_notnull_check = false;
|
boolean is_notnull_check = false;
|
||||||
|
|
||||||
// method annotation, refers to the return value
|
// method annotation, refers to the return value
|
||||||
StructAnnotationAttribute attr =
|
StructAnnotationAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||||
(StructAnnotationAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
|
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
List<AnnotationExprent> annotations = attr.getAnnotations();
|
List<AnnotationExprent> annotations = attr.getAnnotations();
|
||||||
|
|
||||||
for (AnnotationExprent ann : annotations) {
|
for (AnnotationExprent ann : annotations) {
|
||||||
if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
|
if (ann.getClassName().equals("org/jetbrains/annotations/NotNull")) {
|
||||||
is_notnull_check = true;
|
is_notnull_check = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_notnull_check) {
|
return is_notnull_check && removeReturnCheck(stat, mt);
|
||||||
return removeReturnCheck(stat, mt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -205,7 +180,7 @@ public class IdeaNotNullHelper {
|
|||||||
Exprent exprent = stat.getExprents().get(0);
|
Exprent exprent = stat.getExprents().get(0);
|
||||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent exit_exprent = (ExitExprent)exprent;
|
ExitExprent exit_exprent = (ExitExprent)exprent;
|
||||||
if (exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
|
if (exit_exprent.getExitType() == ExitExprent.EXIT_RETURN) {
|
||||||
Exprent exprent_value = exit_exprent.getValue();
|
Exprent exprent_value = exit_exprent.getValue();
|
||||||
//if(exprent_value.type == Exprent.EXPRENT_VAR) {
|
//if(exprent_value.type == Exprent.EXPRENT_VAR) {
|
||||||
// VarExprent var_value = (VarExprent)exprent_value;
|
// VarExprent var_value = (VarExprent)exprent_value;
|
||||||
@ -214,7 +189,7 @@ public class IdeaNotNullHelper {
|
|||||||
Exprent if_condition = ifparent.getHeadexprent().getCondition();
|
Exprent if_condition = ifparent.getHeadexprent().getCondition();
|
||||||
|
|
||||||
if (ifparent.getElsestat() == stat && if_condition.type == Exprent.EXPRENT_FUNCTION &&
|
if (ifparent.getElsestat() == stat && if_condition.type == Exprent.EXPRENT_FUNCTION &&
|
||||||
((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
|
((FunctionExprent)if_condition).getFuncType() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
|
||||||
|
|
||||||
FunctionExprent func = (FunctionExprent)if_condition;
|
FunctionExprent func = (FunctionExprent)if_condition;
|
||||||
Exprent first_param = func.getLstOperands().get(0);
|
Exprent first_param = func.getLstOperands().get(0);
|
||||||
@ -268,7 +243,7 @@ public class IdeaNotNullHelper {
|
|||||||
Exprent exprent = stat.getExprents().get(0);
|
Exprent exprent = stat.getExprents().get(0);
|
||||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||||
ExitExprent exit_exprent = (ExitExprent)exprent;
|
ExitExprent exit_exprent = (ExitExprent)exprent;
|
||||||
if (exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
|
if (exit_exprent.getExitType() == ExitExprent.EXIT_RETURN) {
|
||||||
Exprent exprent_value = exit_exprent.getValue();
|
Exprent exprent_value = exit_exprent.getValue();
|
||||||
|
|
||||||
SequenceStatement sequence = (SequenceStatement)parent;
|
SequenceStatement sequence = (SequenceStatement)parent;
|
||||||
@ -282,7 +257,7 @@ public class IdeaNotNullHelper {
|
|||||||
Exprent if_condition = ifstat.getHeadexprent().getCondition();
|
Exprent if_condition = ifstat.getHeadexprent().getCondition();
|
||||||
|
|
||||||
if (ifstat.iftype == IfStatement.IFTYPE_IF && if_condition.type == Exprent.EXPRENT_FUNCTION &&
|
if (ifstat.iftype == IfStatement.IFTYPE_IF && if_condition.type == Exprent.EXPRENT_FUNCTION &&
|
||||||
((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
|
((FunctionExprent)if_condition).getFuncType() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
|
||||||
|
|
||||||
FunctionExprent func = (FunctionExprent)if_condition;
|
FunctionExprent func = (FunctionExprent)if_condition;
|
||||||
Exprent first_param = func.getLstOperands().get(0);
|
Exprent first_param = func.getLstOperands().get(0);
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
@ -23,43 +9,30 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
public class IfHelper {
|
|
||||||
|
|
||||||
|
|
||||||
|
public final class IfHelper {
|
||||||
public static boolean mergeAllIfs(RootStatement root) {
|
public static boolean mergeAllIfs(RootStatement root) {
|
||||||
|
boolean res = mergeAllIfsRec(root, new HashSet<>());
|
||||||
boolean res = mergeAllIfsRec(root, new HashSet<Integer>());
|
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
SequenceHelper.condenseSequences(root);
|
SequenceHelper.condenseSequences(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean mergeAllIfsRec(Statement stat, Set<? super Integer> setReorderedIfs) {
|
||||||
private static boolean mergeAllIfsRec(Statement stat, HashSet<Integer> setReorderedIfs) {
|
|
||||||
|
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
|
|
||||||
if (stat.getExprents() == null) {
|
if (stat.getExprents() == null) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
|
|
||||||
for (Statement st : stat.getStats()) {
|
for (Statement st : stat.getStats()) {
|
||||||
|
|
||||||
res |= mergeAllIfsRec(st, setReorderedIfs);
|
res |= mergeAllIfsRec(st, setReorderedIfs);
|
||||||
|
|
||||||
// collapse composed if's
|
// collapse composed if's
|
||||||
if (changed = mergeIfs(st, setReorderedIfs)) {
|
if (mergeIfs(st, setReorderedIfs)) {
|
||||||
|
changed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,9 +48,7 @@ public class IfHelper {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean mergeIfs(Statement statement, Set<? super Integer> setReorderedIfs) {
|
||||||
public static boolean mergeIfs(Statement statement, HashSet<Integer> setReorderedIfs) {
|
|
||||||
|
|
||||||
if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
|
if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -85,10 +56,9 @@ public class IfHelper {
|
|||||||
boolean res = false;
|
boolean res = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
boolean updated = false;
|
boolean updated = false;
|
||||||
|
|
||||||
List<Statement> lst = new ArrayList<Statement>();
|
List<Statement> lst = new ArrayList<>();
|
||||||
if (statement.type == Statement.TYPE_IF) {
|
if (statement.type == Statement.TYPE_IF) {
|
||||||
lst.add(statement);
|
lst.add(statement);
|
||||||
}
|
}
|
||||||
@ -99,7 +69,6 @@ public class IfHelper {
|
|||||||
boolean stsingle = (lst.size() == 1);
|
boolean stsingle = (lst.size() == 1);
|
||||||
|
|
||||||
for (Statement stat : lst) {
|
for (Statement stat : lst) {
|
||||||
|
|
||||||
if (stat.type == Statement.TYPE_IF) {
|
if (stat.type == Statement.TYPE_IF) {
|
||||||
IfNode rtnode = buildGraph((IfStatement)stat, stsingle);
|
IfNode rtnode = buildGraph((IfStatement)stat, stsingle);
|
||||||
|
|
||||||
@ -107,22 +76,25 @@ public class IfHelper {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated = collapseIfIf(rtnode)) {
|
if (collapseIfIf(rtnode)) {
|
||||||
|
updated = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setReorderedIfs.contains(stat.id)) {
|
if (!setReorderedIfs.contains(stat.id)) {
|
||||||
|
if (collapseIfElse(rtnode)) {
|
||||||
if (updated = collapseIfElse(rtnode)) {
|
updated = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated = collapseElse(rtnode)) {
|
if (collapseElse(rtnode)) {
|
||||||
|
updated = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated = reorderIf((IfStatement)stat)) {
|
if (reorderIf((IfStatement)stat)) {
|
||||||
|
updated = true;
|
||||||
setReorderedIfs.add(stat.id);
|
setReorderedIfs.add(stat.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -133,14 +105,13 @@ public class IfHelper {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
res |= updated;
|
res = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean collapseIfIf(IfNode rtnode) {
|
private static boolean collapseIfIf(IfNode rtnode) {
|
||||||
|
|
||||||
if (rtnode.edgetypes.get(0) == 0) {
|
if (rtnode.edgetypes.get(0) == 0) {
|
||||||
IfNode ifbranch = rtnode.succs.get(0);
|
IfNode ifbranch = rtnode.succs.get(0);
|
||||||
if (ifbranch.succs.size() == 2) {
|
if (ifbranch.succs.size() == 2) {
|
||||||
@ -158,7 +129,7 @@ public class IfHelper {
|
|||||||
ifchild.removeSuccessor(ifchild.getAllSuccessorEdges().get(0));
|
ifchild.removeSuccessor(ifchild.getAllSuccessorEdges().get(0));
|
||||||
ifparent.getStats().removeWithKey(ifchild.id);
|
ifparent.getStats().removeWithKey(ifchild.id);
|
||||||
|
|
||||||
if (ifbranch.edgetypes.get(0).intValue() == 1) { // target null
|
if (ifbranch.edgetypes.get(0) == 1) { // target null
|
||||||
|
|
||||||
ifparent.setIfstat(null);
|
ifparent.setIfstat(null);
|
||||||
|
|
||||||
@ -196,11 +167,12 @@ public class IfHelper {
|
|||||||
// merge if conditions
|
// merge if conditions
|
||||||
IfExprent statexpr = ifparent.getHeadexprent();
|
IfExprent statexpr = ifparent.getHeadexprent();
|
||||||
|
|
||||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
List<Exprent> lstOperands = new ArrayList<>();
|
||||||
lstOperands.add(statexpr.getCondition());
|
lstOperands.add(statexpr.getCondition());
|
||||||
lstOperands.add(ifchild.getHeadexprent().getCondition());
|
lstOperands.add(ifchild.getHeadexprent().getCondition());
|
||||||
|
|
||||||
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
|
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands, null));
|
||||||
|
statexpr.addBytecodeOffsets(ifchild.getHeadexprent().bytecode);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -212,11 +184,9 @@ public class IfHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean collapseIfElse(IfNode rtnode) {
|
private static boolean collapseIfElse(IfNode rtnode) {
|
||||||
|
if (rtnode.edgetypes.get(0) == 0) {
|
||||||
if (rtnode.edgetypes.get(0).intValue() == 0) {
|
|
||||||
IfNode ifbranch = rtnode.succs.get(0);
|
IfNode ifbranch = rtnode.succs.get(0);
|
||||||
if (ifbranch.succs.size() == 2) {
|
if (ifbranch.succs.size() == 2) {
|
||||||
|
|
||||||
// if-else branch
|
// if-else branch
|
||||||
if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
|
if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
|
||||||
|
|
||||||
@ -229,8 +199,8 @@ public class IfHelper {
|
|||||||
ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
|
ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
|
||||||
ifparent.getStats().removeWithKey(ifchild.id);
|
ifparent.getStats().removeWithKey(ifchild.id);
|
||||||
|
|
||||||
if (ifbranch.edgetypes.get(1).intValue() == 1 &&
|
if (ifbranch.edgetypes.get(1) == 1 &&
|
||||||
ifbranch.edgetypes.get(0).intValue() == 1) { // target null
|
ifbranch.edgetypes.get(0) == 1) { // target null
|
||||||
|
|
||||||
ifparent.setIfstat(null);
|
ifparent.setIfstat(null);
|
||||||
|
|
||||||
@ -249,11 +219,11 @@ public class IfHelper {
|
|||||||
// merge if conditions
|
// merge if conditions
|
||||||
IfExprent statexpr = ifparent.getHeadexprent();
|
IfExprent statexpr = ifparent.getHeadexprent();
|
||||||
|
|
||||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
List<Exprent> lstOperands = new ArrayList<>();
|
||||||
lstOperands.add(statexpr.getCondition());
|
lstOperands.add(statexpr.getCondition());
|
||||||
lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
|
lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, ifchild.getHeadexprent().getCondition(), null));
|
||||||
Arrays.asList(new Exprent[]{ifchild.getHeadexprent().getCondition()})));
|
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands, null));
|
||||||
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
|
statexpr.addBytecodeOffsets(ifchild.getHeadexprent().bytecode);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -264,10 +234,8 @@ public class IfHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean collapseElse(IfNode rtnode) {
|
private static boolean collapseElse(IfNode rtnode) {
|
||||||
|
if (rtnode.edgetypes.get(1) == 0) {
|
||||||
if (rtnode.edgetypes.get(1).intValue() == 0) {
|
|
||||||
IfNode elsebranch = rtnode.succs.get(1);
|
IfNode elsebranch = rtnode.succs.get(1);
|
||||||
if (elsebranch.succs.size() == 2) {
|
if (elsebranch.succs.size() == 2) {
|
||||||
|
|
||||||
@ -304,18 +272,17 @@ public class IfHelper {
|
|||||||
// merge if conditions
|
// merge if conditions
|
||||||
IfExprent statexpr = secondif.getHeadexprent();
|
IfExprent statexpr = secondif.getHeadexprent();
|
||||||
|
|
||||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
List<Exprent> lstOperands = new ArrayList<>();
|
||||||
lstOperands.add(firstif.getHeadexprent().getCondition());
|
lstOperands.add(firstif.getHeadexprent().getCondition());
|
||||||
|
|
||||||
if (path == 2) {
|
if (path == 2) {
|
||||||
lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
|
lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, lstOperands.get(0), null));
|
||||||
Arrays.asList(new Exprent[]{lstOperands.get(0)})));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lstOperands.add(statexpr.getCondition());
|
lstOperands.add(statexpr.getCondition());
|
||||||
|
|
||||||
statexpr
|
statexpr
|
||||||
.setCondition(new FunctionExprent(path == 1 ? FunctionExprent.FUNCTION_COR : FunctionExprent.FUNCTION_CADD, lstOperands));
|
.setCondition(new FunctionExprent(path == 1 ? FunctionExprent.FUNCTION_COR : FunctionExprent.FUNCTION_CADD, lstOperands, null));
|
||||||
|
|
||||||
if (secondif.getFirst().getExprents().isEmpty() &&
|
if (secondif.getFirst().getExprents().isEmpty() &&
|
||||||
!firstif.getFirst().getExprents().isEmpty()) {
|
!firstif.getFirst().getExprents().isEmpty()) {
|
||||||
@ -328,9 +295,7 @@ public class IfHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (elsebranch.succs.size() == 1) {
|
else if (elsebranch.succs.size() == 1) {
|
||||||
|
|
||||||
if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
|
if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
|
||||||
|
|
||||||
IfStatement firstif = (IfStatement)rtnode.value;
|
IfStatement firstif = (IfStatement)rtnode.value;
|
||||||
Statement second = elsebranch.value;
|
Statement second = elsebranch.value;
|
||||||
|
|
||||||
@ -359,7 +324,7 @@ public class IfHelper {
|
|||||||
// negate the if condition
|
// negate the if condition
|
||||||
IfExprent statexpr = firstif.getHeadexprent();
|
IfExprent statexpr = firstif.getHeadexprent();
|
||||||
statexpr
|
statexpr
|
||||||
.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
|
.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, statexpr.getCondition(), null));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -369,9 +334,7 @@ public class IfHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
|
private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
|
||||||
|
|
||||||
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -433,16 +396,14 @@ public class IfHelper {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME: rewrite the entire method!!! keep in mind finally exits!!
|
// FIXME: rewrite the entire method!!! keep in mind finally exits!!
|
||||||
private static boolean reorderIf(IfStatement ifstat) {
|
private static boolean reorderIf(IfStatement ifstat) {
|
||||||
|
|
||||||
if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
|
if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean ifdirect = false, elsedirect = false;
|
boolean ifdirect, elsedirect;
|
||||||
boolean noifstat = false, noelsestat = false;
|
boolean noifstat = false, noelsestat;
|
||||||
boolean ifdirectpath = false, elsedirectpath = false;
|
boolean ifdirectpath = false, elsedirectpath = false;
|
||||||
|
|
||||||
Statement parent = ifstat.getParent();
|
Statement parent = ifstat.getParent();
|
||||||
@ -453,32 +414,20 @@ public class IfHelper {
|
|||||||
if (ifstat.getIfstat() == null) {
|
if (ifstat.getIfstat() == null) {
|
||||||
noifstat = true;
|
noifstat = true;
|
||||||
|
|
||||||
if (ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT) {
|
ifdirect = ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT ||
|
||||||
ifdirect = true;
|
MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
|
||||||
}
|
|
||||||
else {
|
|
||||||
ifdirect = MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
List<StatEdge> lstSuccs = ifstat.getIfstat().getAllSuccessorEdges();
|
List<StatEdge> lstSuccs = ifstat.getIfstat().getAllSuccessorEdges();
|
||||||
if (!lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
|
ifdirect = !lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT ||
|
||||||
ifdirect = true;
|
hasDirectEndEdge(ifstat.getIfstat(), from);
|
||||||
}
|
|
||||||
else {
|
|
||||||
ifdirect = hasDirectEndEdge(ifstat.getIfstat(), from);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement last = parent.type == Statement.TYPE_SEQUENCE ? parent.getStats().getLast() : ifstat;
|
Statement last = parent.type == Statement.TYPE_SEQUENCE ? parent.getStats().getLast() : ifstat;
|
||||||
noelsestat = (last == ifstat);
|
noelsestat = (last == ifstat);
|
||||||
|
|
||||||
if (!last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
|
elsedirect = !last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT ||
|
||||||
elsedirect = true;
|
hasDirectEndEdge(last, from);
|
||||||
}
|
|
||||||
else {
|
|
||||||
elsedirect = hasDirectEndEdge(last, from);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!noelsestat && existsPath(ifstat, ifstat.getAllSuccessorEdges().get(0).getDestination())) {
|
if (!noelsestat && existsPath(ifstat, ifstat.getAllSuccessorEdges().get(0).getDestination())) {
|
||||||
return false;
|
return false;
|
||||||
@ -496,10 +445,9 @@ public class IfHelper {
|
|||||||
if (sttemp == ifstat) {
|
if (sttemp == ifstat) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else if (existsPath(sttemp, next)) {
|
||||||
if (elsedirectpath = existsPath(sttemp, next)) {
|
elsedirectpath = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,7 +457,7 @@ public class IfHelper {
|
|||||||
SequenceStatement sequence = (SequenceStatement)parent;
|
SequenceStatement sequence = (SequenceStatement)parent;
|
||||||
|
|
||||||
// build and cut the new else statement
|
// build and cut the new else statement
|
||||||
List<Statement> lst = new ArrayList<Statement>();
|
List<Statement> lst = new ArrayList<>();
|
||||||
for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
|
for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
|
||||||
Statement sttemp = sequence.getStats().get(i);
|
Statement sttemp = sequence.getStats().get(i);
|
||||||
if (sttemp == ifstat) {
|
if (sttemp == ifstat) {
|
||||||
@ -554,7 +502,7 @@ public class IfHelper {
|
|||||||
|
|
||||||
// negate the if condition
|
// negate the if condition
|
||||||
IfExprent statexpr = ifstat.getHeadexprent();
|
IfExprent statexpr = ifstat.getHeadexprent();
|
||||||
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
|
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, statexpr.getCondition(), null));
|
||||||
|
|
||||||
if (noelsestat) {
|
if (noelsestat) {
|
||||||
StatEdge ifedge = ifstat.getIfEdge();
|
StatEdge ifedge = ifstat.getIfEdge();
|
||||||
@ -597,7 +545,7 @@ public class IfHelper {
|
|||||||
SequenceStatement sequence = (SequenceStatement)parent;
|
SequenceStatement sequence = (SequenceStatement)parent;
|
||||||
|
|
||||||
// build and cut the new else statement
|
// build and cut the new else statement
|
||||||
List<Statement> lst = new ArrayList<Statement>();
|
List<Statement> lst = new ArrayList<>();
|
||||||
for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
|
for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
|
||||||
Statement sttemp = sequence.getStats().get(i);
|
Statement sttemp = sequence.getStats().get(i);
|
||||||
if (sttemp == ifstat) {
|
if (sttemp == ifstat) {
|
||||||
@ -698,9 +646,7 @@ public class IfHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Statement getNextStatement(Statement stat) {
|
private static Statement getNextStatement(Statement stat) {
|
||||||
|
|
||||||
Statement parent = stat.getParent();
|
Statement parent = stat.getParent();
|
||||||
switch (parent.type) {
|
switch (parent.type) {
|
||||||
case Statement.TYPE_ROOT:
|
case Statement.TYPE_ROOT:
|
||||||
@ -722,7 +668,6 @@ public class IfHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean existsPath(Statement from, Statement to) {
|
private static boolean existsPath(Statement from, Statement to) {
|
||||||
|
|
||||||
for (StatEdge edge : to.getAllPredecessorEdges()) {
|
for (StatEdge edge : to.getAllPredecessorEdges()) {
|
||||||
if (from.containsStatementStrict(edge.getSource())) {
|
if (from.containsStatementStrict(edge.getSource())) {
|
||||||
return true;
|
return true;
|
||||||
@ -733,18 +678,17 @@ public class IfHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class IfNode {
|
private static class IfNode {
|
||||||
public Statement value;
|
public final Statement value;
|
||||||
|
public final List<IfNode> succs = new ArrayList<>();
|
||||||
|
public final List<Integer> edgetypes = new ArrayList<>();
|
||||||
|
|
||||||
public List<IfNode> succs = new ArrayList<IfNode>();
|
IfNode(Statement value) {
|
||||||
public List<Integer> edgetypes = new ArrayList<Integer>();
|
|
||||||
|
|
||||||
public IfNode(Statement value) {
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChild(IfNode child, int type) {
|
public void addChild(IfNode child, int type) {
|
||||||
succs.add(child);
|
succs.add(child);
|
||||||
edgetypes.add(new Integer(type));
|
edgetypes.add(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
|
||||||
@ -21,7 +7,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class InlineSingleBlockHelper {
|
public final class InlineSingleBlockHelper {
|
||||||
|
|
||||||
|
|
||||||
public static boolean inlineSingleBlocks(RootStatement root) {
|
public static boolean inlineSingleBlocks(RootStatement root) {
|
||||||
@ -68,7 +54,7 @@ public class InlineSingleBlockHelper {
|
|||||||
Statement parent = source.getParent();
|
Statement parent = source.getParent();
|
||||||
source.removeSuccessor(edge);
|
source.removeSuccessor(edge);
|
||||||
|
|
||||||
List<Statement> lst = new ArrayList<Statement>();
|
List<Statement> lst = new ArrayList<>();
|
||||||
for (int i = seq.getStats().size() - 1; i >= index; i--) {
|
for (int i = seq.getStats().size() - 1; i >= index; i--) {
|
||||||
lst.add(0, seq.getStats().remove(i));
|
lst.add(0, seq.getStats().remove(i));
|
||||||
}
|
}
|
||||||
@ -132,17 +118,14 @@ public class InlineSingleBlockHelper {
|
|||||||
StatEdge edge = lst.get(0);
|
StatEdge edge = lst.get(0);
|
||||||
|
|
||||||
if (sameCatchRanges(edge)) {
|
if (sameCatchRanges(edge)) {
|
||||||
if (edge.explicit) {
|
if (!edge.explicit) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = index; i < seq.getStats().size(); i++) {
|
for (int i = index; i < seq.getStats().size(); i++) {
|
||||||
if (!noExitLabels(seq.getStats().get(i), seq)) {
|
if (!noExitLabels(seq.getStats().get(i), seq)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// FIXME: count labels properly
|
// FIXME: count labels properly
|
||||||
}
|
}
|
||||||
@ -200,21 +183,13 @@ public class InlineSingleBlockHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
|
public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
|
||||||
|
|
||||||
if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
|
if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
|
||||||
|
|
||||||
Statement parent = source.getParent();
|
Statement parent = source.getParent();
|
||||||
|
return parent != closure &&
|
||||||
if (parent == closure) {
|
(parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH || isBreakEdgeLabeled(parent, closure));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH ||
|
|
||||||
isBreakEdgeLabeled(parent, closure);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||||
@ -22,7 +8,7 @@ import java.util.*;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
|
||||||
public class LabelHelper {
|
public final class LabelHelper {
|
||||||
|
|
||||||
|
|
||||||
public static void cleanUpEdges(RootStatement root) {
|
public static void cleanUpEdges(RootStatement root) {
|
||||||
@ -33,7 +19,7 @@ public class LabelHelper {
|
|||||||
|
|
||||||
liftClosures(root);
|
liftClosures(root);
|
||||||
|
|
||||||
lowContinueLabels(root, new HashSet<StatEdge>());
|
lowContinueLabels(root, new HashSet<>());
|
||||||
|
|
||||||
lowClosures(root);
|
lowClosures(root);
|
||||||
}
|
}
|
||||||
@ -63,7 +49,7 @@ public class LabelHelper {
|
|||||||
if (dest.type != Statement.TYPE_DUMMYEXIT) {
|
if (dest.type != Statement.TYPE_DUMMYEXIT) {
|
||||||
Statement parent = dest.getParent();
|
Statement parent = dest.getParent();
|
||||||
|
|
||||||
List<Statement> lst = new ArrayList<Statement>();
|
List<Statement> lst = new ArrayList<>();
|
||||||
if (parent.type == Statement.TYPE_SEQUENCE) {
|
if (parent.type == Statement.TYPE_SEQUENCE) {
|
||||||
lst.addAll(parent.getStats());
|
lst.addAll(parent.getStats());
|
||||||
}
|
}
|
||||||
@ -131,14 +117,14 @@ public class LabelHelper {
|
|||||||
lowContinueLabels(st, edges);
|
lowContinueLabels(st, edges);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lowContinueLabels(st, new HashSet<StatEdge>());
|
lowContinueLabels(st, new HashSet<>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void lowClosures(Statement stat) {
|
public static void lowClosures(Statement stat) {
|
||||||
|
|
||||||
for (StatEdge edge : new ArrayList<StatEdge>(stat.getLabelEdges())) {
|
for (StatEdge edge : new ArrayList<>(stat.getLabelEdges())) {
|
||||||
|
|
||||||
if (edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
|
if (edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
|
||||||
for (Statement st : stat.getStats()) {
|
for (Statement st : stat.getStats()) {
|
||||||
@ -181,7 +167,7 @@ public class LabelHelper {
|
|||||||
|
|
||||||
private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
|
private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
|
||||||
|
|
||||||
HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<Statement, List<StatEdge>>();
|
HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<>();
|
||||||
|
|
||||||
if (stat.getExprents() != null) {
|
if (stat.getExprents() != null) {
|
||||||
return mapEdges;
|
return mapEdges;
|
||||||
@ -279,7 +265,7 @@ public class LabelHelper {
|
|||||||
Statement stlast = swst.getCaseStatements().get(last);
|
Statement stlast = swst.getCaseStatements().get(last);
|
||||||
if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
|
if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
|
||||||
StatEdge edge = stlast.getAllSuccessorEdges().get(0);
|
StatEdge edge = stlast.getAllSuccessorEdges().get(0);
|
||||||
mapEdges.put(edge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{edge})));
|
mapEdges.put(edge.getDestination(), new ArrayList<>(Collections.singletonList(edge)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mapEdges = setExplicitEdges(stlast);
|
mapEdges = setExplicitEdges(stlast);
|
||||||
@ -340,7 +326,7 @@ public class LabelHelper {
|
|||||||
edge.explicit = false;
|
edge.explicit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapEdges.put(newedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{newedge})));
|
mapEdges.put(newedge.getDestination(), new ArrayList<>(Collections.singletonList(newedge)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,7 +374,7 @@ public class LabelHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (statedge != null) {
|
if (statedge != null) {
|
||||||
mapEdges.put(statedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{statedge})));
|
mapEdges.put(statedge.getDestination(), new ArrayList<>(Collections.singletonList(statedge)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,24 +406,26 @@ public class LabelHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<Statement>[] processStatementLabel(Statement stat) {
|
private static class LabelSets {
|
||||||
|
private final Set<Statement> breaks = new HashSet<>();
|
||||||
|
private final Set<Statement> continues = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
HashSet<Statement> setBreak = new HashSet<Statement>();
|
private static LabelSets processStatementLabel(Statement stat) {
|
||||||
HashSet<Statement> setContinue = new HashSet<Statement>();
|
LabelSets sets = new LabelSets();
|
||||||
|
|
||||||
if (stat.getExprents() == null) {
|
if (stat.getExprents() == null) {
|
||||||
for (Statement st : stat.getStats()) {
|
for (Statement st : stat.getStats()) {
|
||||||
HashSet<Statement>[] arr = processStatementLabel(st);
|
LabelSets nested = processStatementLabel(st);
|
||||||
|
sets.breaks.addAll(nested.breaks);
|
||||||
setBreak.addAll(arr[0]);
|
sets.continues.addAll(nested.continues);
|
||||||
setContinue.addAll(arr[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean shieldType = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
|
boolean shieldType = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
|
||||||
if (shieldType) {
|
if (shieldType) {
|
||||||
for (StatEdge edge : stat.getLabelEdges()) {
|
for (StatEdge edge : stat.getLabelEdges()) {
|
||||||
if (edge.explicit && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
|
if (edge.explicit && ((edge.getType() == StatEdge.TYPE_BREAK && sets.breaks.contains(edge.getSource())) ||
|
||||||
(edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
|
(edge.getType() == StatEdge.TYPE_CONTINUE && sets.continues.contains(edge.getSource())))) {
|
||||||
edge.labeled = false;
|
edge.labeled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,16 +433,16 @@ public class LabelHelper {
|
|||||||
|
|
||||||
switch (stat.type) {
|
switch (stat.type) {
|
||||||
case Statement.TYPE_DO:
|
case Statement.TYPE_DO:
|
||||||
setContinue.clear();
|
sets.continues.clear();
|
||||||
case Statement.TYPE_SWITCH:
|
case Statement.TYPE_SWITCH:
|
||||||
setBreak.clear();
|
sets.breaks.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setBreak.add(stat);
|
sets.breaks.add(stat);
|
||||||
setContinue.add(stat);
|
sets.continues.add(stat);
|
||||||
|
|
||||||
return new HashSet[] { setBreak, setContinue };
|
return sets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void replaceContinueWithBreak(Statement stat) {
|
public static void replaceContinueWithBreak(Statement stat) {
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
/*
|
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
package org.jetbrains.java.decompiler.modules.decompiler;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
|
||||||
@ -25,7 +11,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
public class LoopExtractHelper {
|
public final class LoopExtractHelper {
|
||||||
|
|
||||||
|
|
||||||
public static boolean extractLoops(Statement root) {
|
public static boolean extractLoops(Statement root) {
|
||||||
@ -72,9 +58,7 @@ public class LoopExtractHelper {
|
|||||||
return res ? 1 : 0;
|
return res ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean extractLoop(DoStatement stat) {
|
private static boolean extractLoop(DoStatement stat) {
|
||||||
|
|
||||||
if (stat.getLooptype() != DoStatement.LOOP_DO) {
|
if (stat.getLooptype() != DoStatement.LOOP_DO) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -85,12 +69,7 @@ public class LoopExtractHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extractLastIf(stat)) {
|
return extractLastIf(stat) || extractFirstIf(stat);
|
||||||
return extractFirstIf(stat);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean extractLastIf(DoStatement stat) {
|
private static boolean extractLastIf(DoStatement stat) {
|
||||||
@ -189,7 +168,7 @@ public class LoopExtractHelper {
|
|||||||
|
|
||||||
loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target));
|
loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target));
|
||||||
|
|
||||||
for (StatEdge edge : new ArrayList<StatEdge>(block.getLabelEdges())) {
|
for (StatEdge edge : new ArrayList<>(block.getLabelEdges())) {
|
||||||
if (edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) {
|
if (edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) {
|
||||||
loop.addLabeledEdge(edge);
|
loop.addLabeledEdge(edge);
|
||||||
}
|
}
|
||||||
|
@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2014 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jetbrains.java.decompiler.modules.decompiler;
|
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class LowBreakHelper {
|
|
||||||
|
|
||||||
public static void lowBreakLabels(Statement root) {
|
|
||||||
|
|
||||||
lowBreakLabelsRec(root);
|
|
||||||
|
|
||||||
liftBreakLabels(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void lowBreakLabelsRec(Statement stat) {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
|
|
||||||
for (StatEdge edge : stat.getLabelEdges()) {
|
|
||||||
if (edge.getType() == StatEdge.TYPE_BREAK) {
|
|
||||||
Statement minclosure = getMinClosure(stat, edge.getSource());
|
|
||||||
if (minclosure != stat) {
|
|
||||||
minclosure.addLabeledEdge(edge);
|
|
||||||
edge.labeled = isBreakEdgeLabeled(edge.getSource(), minclosure);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Statement st : stat.getStats()) {
|
|
||||||
lowBreakLabelsRec(st);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
|
|
||||||
|
|
||||||
if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
|
|
||||||
|
|
||||||
Statement parent = source.getParent();
|
|
||||||
|
|
||||||
if (parent == closure) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return isBreakEdgeLabeled(parent, closure) ||
|
|
||||||
(parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Statement getMinClosure(Statement closure, Statement source) {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
Statement newclosure = null;
|
|
||||||
|
|
||||||
switch (closure.type) {
|
|
||||||
case Statement.TYPE_SEQUENCE:
|
|
||||||
Statement last = closure.getStats().getLast();
|
|
||||||
|
|
||||||
if (isOkClosure(closure, source, last)) {
|
|
||||||
newclosure = last;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Statement.TYPE_IF:
|
|
||||||
IfStatement ifclosure = (IfStatement)closure;
|
|
||||||
if (isOkClosure(closure, source, ifclosure.getIfstat())) {
|
|
||||||
newclosure = ifclosure.getIfstat();
|
|
||||||
}
|
|
||||||
else if (isOkClosure(closure, source, ifclosure.getElsestat())) {
|
|
||||||
newclosure = ifclosure.getElsestat();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Statement.TYPE_TRYCATCH:
|
|
||||||
for (Statement st : closure.getStats()) {
|
|
||||||
if (isOkClosure(closure, source, st)) {
|
|
||||||
newclosure = st;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Statement.TYPE_SYNCRONIZED:
|
|
||||||
Statement body = ((SynchronizedStatement)closure).getBody();
|
|
||||||
|
|
||||||
if (isOkClosure(closure, source, body)) {
|
|
||||||
newclosure = body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newclosure == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
closure = newclosure;
|
|
||||||
}
|
|
||||||
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isOkClosure(Statement closure, Statement source, Statement stat) {
|
|
||||||
|
|
||||||
boolean ok = false;
|
|
||||||
|
|
||||||
if (stat != null && stat.containsStatementStrict(source)) {
|
|
||||||
|
|
||||||
List<StatEdge> lst = stat.getAllSuccessorEdges();
|
|
||||||
|
|
||||||
ok = lst.isEmpty();
|
|
||||||
if (!ok) {
|
|
||||||
StatEdge edge = lst.get(0);
|
|
||||||
ok = (edge.closure == closure && edge.getType() == StatEdge.TYPE_BREAK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void liftBreakLabels(Statement stat) {
|
|
||||||
|
|
||||||
for (Statement st : stat.getStats()) {
|
|
||||||
liftBreakLabels(st);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
|
|
||||||
for (StatEdge edge : stat.getLabelEdges()) {
|
|
||||||
if (edge.explicit && edge.labeled && edge.getType() == StatEdge.TYPE_BREAK) {
|
|
||||||
|
|
||||||
Statement newclosure = getMaxBreakLift(stat, edge);
|
|
||||||
|
|
||||||
if (newclosure != null) {
|
|
||||||
newclosure.addLabeledEdge(edge);
|
|
||||||
edge.labeled = isBreakEdgeLabeled(edge.getSource(), newclosure);
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Statement getMaxBreakLift(Statement stat, StatEdge edge) {
|
|
||||||
|
|
||||||
Statement closure = null;
|
|
||||||
Statement newclosure = stat;
|
|
||||||
|
|
||||||
while ((newclosure = getNextBreakLift(newclosure, edge)) != null) {
|
|
||||||
closure = newclosure;
|
|
||||||
}
|
|
||||||
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Statement getNextBreakLift(Statement stat, StatEdge edge) {
|
|
||||||
|
|
||||||
Statement closure = stat.getParent();
|
|
||||||
|
|
||||||
while (closure != null && !closure.containsStatementStrict(edge.getDestination())) {
|
|
||||||
|
|
||||||
boolean labeled = isBreakEdgeLabeled(edge.getSource(), closure);
|
|
||||||
if (closure.isLabeled() || !labeled) {
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
closure = closure.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user