[*] 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>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>eclipse-formatter</artifactId>
|
||||
<version>3.14.0-spigotmc-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>./src</sourceDirectory>
|
||||
|
||||
<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>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<source>9</source>
|
||||
<target>9</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -1,31 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code;
|
||||
|
||||
@SuppressWarnings({"unused", "SpellCheckingInspection"})
|
||||
public interface CodeConstants {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// BYTECODE VERSIONS
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int BYTECODE_JAVA_LE_4 = 1;
|
||||
int BYTECODE_JAVA_5 = 2;
|
||||
int BYTECODE_JAVA_6 = 3;
|
||||
int BYTECODE_JAVA_7 = 4;
|
||||
int BYTECODE_JAVA_8 = 5;
|
||||
int BYTECODE_JAVA_LE_4 = 48;
|
||||
int BYTECODE_JAVA_5 = 49;
|
||||
int BYTECODE_JAVA_6 = 50;
|
||||
int BYTECODE_JAVA_7 = 51;
|
||||
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
|
||||
@ -63,20 +54,6 @@ public interface CodeConstants {
|
||||
int TYPE_FAMILY_DOUBLE = 5;
|
||||
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
|
||||
// ----------------------------------------------------------------------
|
||||
@ -87,6 +64,7 @@ public interface CodeConstants {
|
||||
int ACC_STATIC = 0x0008;
|
||||
int ACC_FINAL = 0x0010;
|
||||
int ACC_SYNCHRONIZED = 0x0020;
|
||||
int ACC_OPEN = 0x0020;
|
||||
int ACC_NATIVE = 0x0100;
|
||||
int ACC_ABSTRACT = 0x0400;
|
||||
int ACC_STRICT = 0x0800;
|
||||
@ -97,6 +75,8 @@ public interface CodeConstants {
|
||||
int ACC_SYNTHETIC = 0x1000;
|
||||
int ACC_ANNOTATION = 0x2000;
|
||||
int ACC_ENUM = 0x4000;
|
||||
int ACC_MANDATED = 0x8000;
|
||||
int ACC_MODULE = 0x8000;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// CLASS FLAGS
|
||||
@ -105,17 +85,6 @@ public interface CodeConstants {
|
||||
int ACC_SUPER = 0x0020;
|
||||
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
|
||||
// ----------------------------------------------------------------------
|
||||
@ -145,6 +114,8 @@ public interface CodeConstants {
|
||||
int CONSTANT_MethodHandle = 15;
|
||||
int CONSTANT_MethodType = 16;
|
||||
int CONSTANT_InvokeDynamic = 18;
|
||||
int CONSTANT_Module = 19;
|
||||
int CONSTANT_Package = 20;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// MethodHandle reference_kind values
|
||||
@ -351,7 +322,6 @@ public interface CodeConstants {
|
||||
int opc_invokestatic = 184;
|
||||
int opc_invokeinterface = 185;
|
||||
int opc_invokedynamic = 186;
|
||||
int opc_xxxunusedxxx = 186;
|
||||
int opc_new = 187;
|
||||
int opc_newarray = 188;
|
||||
int opc_anewarray = 189;
|
||||
@ -367,4 +337,7 @@ public interface CodeConstants {
|
||||
int opc_ifnonnull = 199;
|
||||
int opc_goto_w = 200;
|
||||
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-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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code;
|
||||
|
||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ExceptionHandler {
|
||||
|
||||
public int from = 0;
|
||||
public int to = 0;
|
||||
public int handler = 0;
|
||||
@ -30,32 +12,12 @@ public class ExceptionHandler {
|
||||
public int to_instr = 0;
|
||||
public int handler_instr = 0;
|
||||
|
||||
public int class_index = 0;
|
||||
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() {
|
||||
|
||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||
|
||||
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 +
|
||||
"exceptionClass: " + exceptionClass + new_line_separator;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.interpreter.Util;
|
||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ExceptionTable {
|
||||
public static final ExceptionTable EMPTY = new ExceptionTable(Collections.emptyList());
|
||||
|
||||
private List<ExceptionHandler> handlers = new ArrayList<ExceptionHandler>();
|
||||
|
||||
public ExceptionTable() {
|
||||
}
|
||||
private final List<ExceptionHandler> handlers;
|
||||
|
||||
public ExceptionTable(List<ExceptionHandler> 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() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code;
|
||||
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
@ -25,7 +11,7 @@ public class FullInstructionSequence extends InstructionSequence {
|
||||
// *****************************************************************************
|
||||
|
||||
public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
|
||||
this.collinstr = collinstr;
|
||||
super(collinstr);
|
||||
this.exceptionTable = extable;
|
||||
|
||||
// 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-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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||
|
||||
public class Instruction implements CodeConstants {
|
||||
|
||||
// *****************************************************************************
|
||||
// public fields
|
||||
// *****************************************************************************
|
||||
|
||||
public int opcode;
|
||||
|
||||
public int group = CodeConstants.GROUP_GENERAL;
|
||||
|
||||
public boolean wide = false;
|
||||
|
||||
public int bytecode_version = BYTECODE_JAVA_LE_4;
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
|
||||
private int[] operands = null;
|
||||
|
||||
// *****************************************************************************
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
|
||||
public Instruction() {
|
||||
public static Instruction create(int opcode, boolean wide, int group, int bytecodeVersion, int[] operands) {
|
||||
if (opcode >= opc_ifeq && opcode <= opc_if_acmpne ||
|
||||
opcode == opc_ifnull || opcode == opc_ifnonnull ||
|
||||
opcode == opc_jsr || opcode == opc_jsr_w ||
|
||||
opcode == opc_goto || opcode == opc_goto_w) {
|
||||
return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands);
|
||||
}
|
||||
else if (opcode == opc_tableswitch || opcode == opc_lookupswitch) {
|
||||
return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands);
|
||||
}
|
||||
else {
|
||||
return new Instruction(opcode, group, wide, bytecodeVersion, operands);
|
||||
}
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return 1;
|
||||
public static boolean equals(Instruction i1, Instruction i2) {
|
||||
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() {
|
||||
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];
|
||||
}
|
||||
|
||||
public Instruction clone() {
|
||||
return ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, operands == null ? null : operands.clone());
|
||||
public boolean canFallThrough() {
|
||||
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() {
|
||||
|
||||
String res = wide ? "@wide " : "";
|
||||
res += "@" + ConstantsUtil.getName(opcode);
|
||||
StringBuilder res = new StringBuilder();
|
||||
if (wide) res.append("@wide ");
|
||||
res.append("@").append(TextUtil.getInstructionName(opcode));
|
||||
|
||||
int len = operandsCount();
|
||||
for (int i = 0; i < len; i++) {
|
||||
int op = operands[i];
|
||||
if (op < 0) {
|
||||
res += " -" + Integer.toHexString(-op);
|
||||
res.append(" -").append(Integer.toHexString(-op));
|
||||
}
|
||||
else {
|
||||
res += " " + Integer.toHexString(op);
|
||||
res.append(" ").append(Integer.toHexString(op));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public boolean canFallthrough() {
|
||||
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
|
||||
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||
public Instruction clone() {
|
||||
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-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.
|
||||
*/
|
||||
// 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.code;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.interpreter.Util;
|
||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||
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 {
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
|
||||
protected VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
|
||||
protected final VBStyleCollection<Instruction, Integer> collinstr;
|
||||
|
||||
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
|
||||
// *****************************************************************************
|
||||
|
||||
// to nbe overwritten
|
||||
@Override
|
||||
public InstructionSequence clone() {
|
||||
return null;
|
||||
}
|
||||
@ -52,7 +38,7 @@ public abstract class InstructionSequence {
|
||||
public void clear() {
|
||||
collinstr.clear();
|
||||
pointer = 0;
|
||||
exceptionTable = new ExceptionTable();
|
||||
exceptionTable = ExceptionTable.EMPTY;
|
||||
}
|
||||
|
||||
public void addInstruction(Instruction inst, int offset) {
|
||||
@ -73,8 +59,10 @@ public abstract class InstructionSequence {
|
||||
collinstr.remove(index);
|
||||
}
|
||||
|
||||
public Instruction getCurrentInstr() {
|
||||
return collinstr.get(pointer);
|
||||
public void removeLast() {
|
||||
if (!collinstr.isEmpty()) {
|
||||
collinstr.remove(collinstr.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public Instruction getInstr(int index) {
|
||||
@ -85,16 +73,12 @@ public abstract class InstructionSequence {
|
||||
return collinstr.getLast();
|
||||
}
|
||||
|
||||
public int getCurrentOffset() {
|
||||
return collinstr.getKey(pointer).intValue();
|
||||
}
|
||||
|
||||
public int getOffset(int index) {
|
||||
return collinstr.getKey(index).intValue();
|
||||
public int getOffset(int index) {
|
||||
return collinstr.getKey(index);
|
||||
}
|
||||
|
||||
public int getPointerByAbsOffset(int offset) {
|
||||
Integer absoffset = new Integer(offset);
|
||||
Integer absoffset = offset;
|
||||
if (collinstr.containsKey(absoffset)) {
|
||||
return collinstr.getIndexByKey(absoffset);
|
||||
}
|
||||
@ -104,7 +88,7 @@ public int getOffset(int index) {
|
||||
}
|
||||
|
||||
public int getPointerByRelOffset(int offset) {
|
||||
Integer absoffset = new Integer(collinstr.getKey(pointer).intValue() + offset);
|
||||
Integer absoffset = collinstr.getKey(pointer) + offset;
|
||||
if (collinstr.containsKey(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() {
|
||||
return collinstr.size();
|
||||
}
|
||||
@ -143,7 +120,7 @@ public int getOffset(int index) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
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(": ");
|
||||
buf.append(collinstr.get(i).toString());
|
||||
@ -153,58 +130,6 @@ public int getOffset(int index) {
|
||||
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
|
||||
// *****************************************************************************
|
||||
@ -220,8 +145,4 @@ public int getOffset(int index) {
|
||||
public ExceptionTable getExceptionTable() {
|
||||
return exceptionTable;
|
||||
}
|
||||
|
||||
public void setExceptionTable(ExceptionTable exceptionTable) {
|
||||
this.exceptionTable = exceptionTable;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
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 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) {
|
||||
destination = seq.getPointerByRelOffset(this.getOperand(0));
|
||||
destination = seq.getPointerByRelOffset(this.operand(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JumpInstruction clone() {
|
||||
JumpInstruction newinstr = (JumpInstruction)super.clone();
|
||||
|
||||
newinstr.destination = destination;
|
||||
return newinstr;
|
||||
JumpInstruction copy = (JumpInstruction)super.clone();
|
||||
copy.destination = destination;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.code;
|
||||
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
@ -23,17 +9,14 @@ public class SimpleInstructionSequence extends InstructionSequence {
|
||||
}
|
||||
|
||||
public SimpleInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
|
||||
this.collinstr = collinstr;
|
||||
super(collinstr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleInstructionSequence clone() {
|
||||
SimpleInstructionSequence newseq = new SimpleInstructionSequence(collinstr.clone());
|
||||
newseq.setPointer(this.getPointer());
|
||||
|
||||
return newseq;
|
||||
}
|
||||
|
||||
public void removeInstruction(int index) {
|
||||
collinstr.remove(index);
|
||||
}
|
||||
}
|
||||
|
@ -1,97 +1,61 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code;
|
||||
|
||||
/*
|
||||
* opc_tableswitch, lookupswitch
|
||||
*/
|
||||
|
||||
public class SwitchInstruction extends Instruction {
|
||||
|
||||
private int[] destinations;
|
||||
|
||||
private int[] values;
|
||||
private int defaultDestination;
|
||||
|
||||
private int defaultdest;
|
||||
|
||||
public SwitchInstruction() {
|
||||
public SwitchInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
|
||||
super(opcode, group, wide, bytecodeVersion, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initInstruction(InstructionSequence seq) {
|
||||
defaultDestination = seq.getPointerByRelOffset(operands[0]);
|
||||
|
||||
int pref = (opcode == CodeConstants.opc_tableswitch ? 3 : 2);
|
||||
int len = this.getOperands().length - pref;
|
||||
defaultdest = seq.getPointerByRelOffset(this.getOperand(0));
|
||||
|
||||
int prefix = opcode == CodeConstants.opc_tableswitch ? 3 : 2;
|
||||
int len = operands.length - prefix;
|
||||
int low = 0;
|
||||
|
||||
if (opcode == CodeConstants.opc_lookupswitch) {
|
||||
len /= 2;
|
||||
}
|
||||
else {
|
||||
low = this.getOperand(1);
|
||||
low = operands[1];
|
||||
}
|
||||
|
||||
destinations = new int[len];
|
||||
values = new int[len];
|
||||
|
||||
for (int i = 0, k = 0; i < len; i++, k++) {
|
||||
if (opcode == CodeConstants.opc_lookupswitch) {
|
||||
values[i] = this.getOperand(pref + k);
|
||||
values[i] = operands[prefix + k];
|
||||
k++;
|
||||
}
|
||||
else {
|
||||
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() {
|
||||
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() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public void setValues(int[] values) {
|
||||
this.values = values;
|
||||
public int getDefaultDestination() {
|
||||
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-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.
|
||||
*/
|
||||
// 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.code.cfg;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.Instruction;
|
||||
@ -30,8 +16,7 @@ public class BasicBlock implements IGraphNode {
|
||||
// public fields
|
||||
// *****************************************************************************
|
||||
|
||||
public int id = 0;
|
||||
|
||||
public int id;
|
||||
public int mark = 0;
|
||||
|
||||
// *****************************************************************************
|
||||
@ -40,19 +25,11 @@ public class BasicBlock implements IGraphNode {
|
||||
|
||||
private InstructionSequence seq = new SimpleInstructionSequence();
|
||||
|
||||
private List<BasicBlock> preds = new ArrayList<BasicBlock>();
|
||||
|
||||
private List<BasicBlock> succs = new ArrayList<BasicBlock>();
|
||||
|
||||
private List<Integer> instrOldOffsets = new ArrayList<Integer>();
|
||||
|
||||
private List<BasicBlock> predExceptions = new ArrayList<BasicBlock>();
|
||||
|
||||
private List<BasicBlock> succExceptions = new ArrayList<BasicBlock>();
|
||||
|
||||
|
||||
public BasicBlock() {
|
||||
}
|
||||
private final List<BasicBlock> preds = new ArrayList<>();
|
||||
private final List<BasicBlock> succs = new ArrayList<>();
|
||||
private final List<Integer> instrOldOffsets = new ArrayList<>();
|
||||
private final List<BasicBlock> predExceptions = new ArrayList<>();
|
||||
private final List<BasicBlock> succExceptions = new ArrayList<>();
|
||||
|
||||
public BasicBlock(int id) {
|
||||
this.id = id;
|
||||
@ -62,24 +39,17 @@ public class BasicBlock implements IGraphNode {
|
||||
// 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.setInstrOldOffsets(new ArrayList<Integer>(instrOldOffsets));
|
||||
block.instrOldOffsets.addAll(instrOldOffsets);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
public void free() {
|
||||
preds.clear();
|
||||
succs.clear();
|
||||
instrOldOffsets.clear();
|
||||
succExceptions.clear();
|
||||
seq = new SimpleInstructionSequence();
|
||||
}
|
||||
|
||||
public Instruction getInstruction(int index) {
|
||||
return seq.getInstr(index);
|
||||
}
|
||||
@ -110,7 +80,7 @@ public class BasicBlock implements IGraphNode {
|
||||
}
|
||||
|
||||
public void removePredecessor(BasicBlock block) {
|
||||
while (preds.remove(block)) ;
|
||||
while (preds.remove(block)) /**/;
|
||||
}
|
||||
|
||||
public void addSuccessor(BasicBlock block) {
|
||||
@ -119,11 +89,11 @@ public class BasicBlock implements IGraphNode {
|
||||
}
|
||||
|
||||
public void removeSuccessor(BasicBlock block) {
|
||||
while (succs.remove(block)) ;
|
||||
while (succs.remove(block)) /**/;
|
||||
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) {
|
||||
for (int i = 0; i < succs.size(); i++) {
|
||||
if (succs.get(i).id == oldBlock.id) {
|
||||
@ -147,7 +117,7 @@ public class BasicBlock implements IGraphNode {
|
||||
}
|
||||
|
||||
public void removePredecessorException(BasicBlock block) {
|
||||
while (predExceptions.remove(block)) ;
|
||||
while (predExceptions.remove(block)) /**/;
|
||||
}
|
||||
|
||||
public void addSuccessorException(BasicBlock block) {
|
||||
@ -158,7 +128,7 @@ public class BasicBlock implements IGraphNode {
|
||||
}
|
||||
|
||||
public void removeSuccessorException(BasicBlock block) {
|
||||
while (succExceptions.remove(block)) ;
|
||||
while (succExceptions.remove(block)) /**/;
|
||||
block.removePredecessorException(this);
|
||||
}
|
||||
|
||||
@ -173,27 +143,6 @@ public class BasicBlock implements IGraphNode {
|
||||
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) {
|
||||
for (BasicBlock succ : succs) {
|
||||
if (succ.id == block.id) {
|
||||
@ -203,15 +152,6 @@ public class BasicBlock implements IGraphNode {
|
||||
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
|
||||
// *****************************************************************************
|
||||
@ -220,12 +160,9 @@ public class BasicBlock implements IGraphNode {
|
||||
return instrOldOffsets;
|
||||
}
|
||||
|
||||
public void setInstrOldOffsets(List<Integer> instrInds) {
|
||||
this.instrOldOffsets = instrInds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IGraphNode> getPredecessors() {
|
||||
List<BasicBlock> lst = new ArrayList<BasicBlock>(preds);
|
||||
List<BasicBlock> lst = new ArrayList<>(preds);
|
||||
lst.addAll(predExceptions);
|
||||
return lst;
|
||||
}
|
||||
@ -234,10 +171,6 @@ public class BasicBlock implements IGraphNode {
|
||||
return preds;
|
||||
}
|
||||
|
||||
public void setPreds(List<BasicBlock> preds) {
|
||||
this.preds = preds;
|
||||
}
|
||||
|
||||
public InstructionSequence getSeq() {
|
||||
return seq;
|
||||
}
|
||||
@ -250,25 +183,11 @@ public class BasicBlock implements IGraphNode {
|
||||
return succs;
|
||||
}
|
||||
|
||||
public void setSuccs(List<BasicBlock> succs) {
|
||||
this.succs = succs;
|
||||
}
|
||||
|
||||
|
||||
public List<BasicBlock> getSuccExceptions() {
|
||||
return succExceptions;
|
||||
}
|
||||
|
||||
|
||||
public void setSuccExceptions(List<BasicBlock> succExceptions) {
|
||||
this.succExceptions = succExceptions;
|
||||
}
|
||||
|
||||
public List<BasicBlock> getPredExceptions() {
|
||||
return predExceptions;
|
||||
}
|
||||
|
||||
public void setPredExceptions(List<BasicBlock> predExceptions) {
|
||||
this.predExceptions = predExceptions;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +1,11 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.code.cfg;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.*;
|
||||
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
|
||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||
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.consts.ConstantPool;
|
||||
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
|
||||
@ -47,7 +34,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
private Map<BasicBlock, BasicBlock> subroutines;
|
||||
|
||||
private Set<BasicBlock> finallyExits = new HashSet<BasicBlock>();
|
||||
private final Set<BasicBlock> finallyExits = new HashSet<>();
|
||||
|
||||
// *****************************************************************************
|
||||
// constructors
|
||||
@ -62,19 +49,6 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
|
||||
public void free() {
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
block.free();
|
||||
}
|
||||
|
||||
blocks.clear();
|
||||
first = null;
|
||||
last = null;
|
||||
exceptions.clear();
|
||||
finallyExits.clear();
|
||||
}
|
||||
|
||||
public void removeMarkers() {
|
||||
for (BasicBlock block : blocks) {
|
||||
block.mark = 0;
|
||||
@ -82,6 +56,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (blocks == null) return "Empty";
|
||||
|
||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||
|
||||
@ -93,12 +68,11 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
buf.append("----- Edges -----").append(new_line_separator);
|
||||
|
||||
List<BasicBlock> suc = block.getSuccs();
|
||||
for (int j = 0; j < suc.size(); j++) {
|
||||
buf.append(">>>>>>>>(regular) Block ").append(suc.get(j).id).append(new_line_separator);
|
||||
for (BasicBlock aSuc : suc) {
|
||||
buf.append(">>>>>>>>(regular) Block ").append(aSuc.id).append(new_line_separator);
|
||||
}
|
||||
suc = block.getSuccExceptions();
|
||||
for (int j = 0; j < suc.size(); j++) {
|
||||
BasicBlock handler = suc.get(j);
|
||||
for (BasicBlock handler : suc) {
|
||||
ExceptionRangeCFG range = getExceptionRange(handler, block);
|
||||
|
||||
if (range == null) {
|
||||
@ -123,9 +97,9 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public void inlineJsr(StructMethod mt) {
|
||||
public void inlineJsr(StructClass cl, StructMethod mt) {
|
||||
processJsr();
|
||||
removeJsr(mt);
|
||||
removeJsr(cl, mt);
|
||||
|
||||
removeMarkers();
|
||||
|
||||
@ -169,13 +143,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<Entry<BasicBlock, BasicBlock>> it = subroutines.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<BasicBlock, BasicBlock> ent = it.next();
|
||||
if (ent.getKey() == block || ent.getValue() == block) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
subroutines.entrySet().removeIf(ent -> ent.getKey() == block || ent.getValue() == block);
|
||||
}
|
||||
|
||||
public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) {
|
||||
@ -224,7 +192,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
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);
|
||||
|
||||
blocks = colBlocks;
|
||||
@ -243,7 +211,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
int len = seq.length();
|
||||
short[] inststates = new short[len];
|
||||
|
||||
Set<Integer> excSet = new HashSet<Integer>();
|
||||
Set<Integer> excSet = new HashSet<>();
|
||||
|
||||
for (ExceptionHandler handler : seq.getExceptionTable().getHandlers()) {
|
||||
excSet.add(handler.from_instr);
|
||||
@ -255,7 +223,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
// exception blocks
|
||||
if (excSet.contains(new Integer(i))) {
|
||||
if (excSet.contains(i)) {
|
||||
inststates[i] = 1;
|
||||
}
|
||||
|
||||
@ -274,7 +242,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
for (int j = dests.length - 1; j >= 0; j--) {
|
||||
inststates[dests[j]] = 1;
|
||||
}
|
||||
inststates[swinstr.getDefaultdest()] = 1;
|
||||
inststates[swinstr.getDefaultDestination()] = 1;
|
||||
if (i + 1 < len) {
|
||||
inststates[i + 1] = 1;
|
||||
}
|
||||
@ -292,10 +260,10 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
InstructionSequence instrseq,
|
||||
Map<Integer, BasicBlock> mapInstrBlocks) {
|
||||
|
||||
VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<BasicBlock, Integer>();
|
||||
VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<>();
|
||||
|
||||
InstructionSequence currseq = null;
|
||||
ArrayList<Integer> lstOffs = null;
|
||||
List<Integer> lstOffs = null;
|
||||
|
||||
int len = startblock.length;
|
||||
short counter = 0;
|
||||
@ -305,14 +273,11 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
if (startblock[i] == 1) {
|
||||
currentBlock = new BasicBlock();
|
||||
currentBlock.id = ++counter;
|
||||
currentBlock = new BasicBlock(++counter);
|
||||
|
||||
currseq = new SimpleInstructionSequence();
|
||||
lstOffs = new ArrayList<Integer>();
|
||||
currseq = currentBlock.getSeq();
|
||||
lstOffs = currentBlock.getInstrOldOffsets();
|
||||
|
||||
currentBlock.setSeq(currseq);
|
||||
currentBlock.setInstrOldOffsets(lstOffs);
|
||||
col.addWithKey(currentBlock, currentBlock.id);
|
||||
|
||||
blockoffset = instrseq.getOffset(i);
|
||||
@ -338,7 +303,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
BasicBlock block = lstbb.get(i);
|
||||
Instruction instr = block.getLastInstruction();
|
||||
|
||||
boolean fallthrough = instr.canFallthrough();
|
||||
boolean fallthrough = instr.canFallThrough();
|
||||
BasicBlock bTemp;
|
||||
|
||||
switch (instr.group) {
|
||||
@ -352,10 +317,10 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
SwitchInstruction sinstr = (SwitchInstruction)instr;
|
||||
int[] dests = sinstr.getDestinations();
|
||||
|
||||
bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest());
|
||||
bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultDestination());
|
||||
block.addSuccessor(bTemp);
|
||||
for (int j = 0; j < dests.length; j++) {
|
||||
bTemp = mapInstrBlocks.get(dests[j]);
|
||||
for (int dest1 : dests) {
|
||||
bTemp = mapInstrBlocks.get(dest1);
|
||||
block.addSuccessor(bTemp);
|
||||
}
|
||||
}
|
||||
@ -369,9 +334,9 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
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()) {
|
||||
|
||||
@ -387,7 +352,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
}
|
||||
else {
|
||||
|
||||
List<BasicBlock> protectedRange = new ArrayList<BasicBlock>();
|
||||
List<BasicBlock> protectedRange = new ArrayList<>();
|
||||
for (int j = from.id; j < to.id; j++) {
|
||||
BasicBlock block = blocks.getWithKey(j);
|
||||
protectedRange.add(block);
|
||||
@ -396,7 +361,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null
|
||||
? null
|
||||
: Arrays.asList(handler.exceptionClass));
|
||||
: Collections.singletonList(handler.exceptionClass));
|
||||
mapRanges.put(key, range);
|
||||
|
||||
exceptions.add(range);
|
||||
@ -406,19 +371,19 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
private void setSubroutineEdges() {
|
||||
|
||||
final Map<BasicBlock, BasicBlock> subroutines = new HashMap<BasicBlock, BasicBlock>();
|
||||
final Map<BasicBlock, BasicBlock> subroutines = new LinkedHashMap<>();
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
|
||||
if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) {
|
||||
|
||||
LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
|
||||
LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<LinkedList<BasicBlock>>();
|
||||
LinkedList<BasicBlock> stack = new LinkedList<>();
|
||||
LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<>();
|
||||
|
||||
Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
|
||||
Set<BasicBlock> setVisited = new HashSet<>();
|
||||
|
||||
stack.add(block);
|
||||
stackJsrStacks.add(new LinkedList<BasicBlock>());
|
||||
stackJsrStacks.add(new LinkedList<>());
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
|
||||
@ -451,7 +416,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
for (BasicBlock succ : node.getSuccs()) {
|
||||
if (!setVisited.contains(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 Set<BasicBlock> range;
|
||||
private final BasicBlock ret;
|
||||
@ -482,7 +447,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
private int processJsrRanges() {
|
||||
|
||||
List<JsrRecord> lstJsrAll = new ArrayList<JsrRecord>();
|
||||
List<JsrRecord> lstJsrAll = new ArrayList<>();
|
||||
|
||||
// get all jsr ranges
|
||||
for (Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()) {
|
||||
@ -494,7 +459,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
// sort ranges
|
||||
// FIXME: better sort order
|
||||
List<JsrRecord> lstJsr = new ArrayList<JsrRecord>();
|
||||
List<JsrRecord> lstJsr = new ArrayList<>();
|
||||
for (JsrRecord arr : lstJsrAll) {
|
||||
int i = 0;
|
||||
for (; i < lstJsr.size(); i++) {
|
||||
@ -516,7 +481,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
Set<BasicBlock> set1 = arr1.range;
|
||||
|
||||
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);
|
||||
|
||||
if (!setc.isEmpty()) {
|
||||
@ -532,9 +497,9 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
|
||||
List<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
|
||||
Map<Integer, BasicBlock> mapNewNodes = new HashMap<Integer, BasicBlock>();
|
||||
List<BasicBlock> lstNodes = new LinkedList<>();
|
||||
Map<Integer, BasicBlock> mapNewNodes = new HashMap<>();
|
||||
|
||||
lstNodes.add(jsr);
|
||||
mapNewNodes.put(jsr.id, jsr);
|
||||
@ -633,9 +598,8 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
node.replaceSuccessor(child, mapNewNodes.get(childid));
|
||||
}
|
||||
else if (common_blocks.contains(child)) {
|
||||
|
||||
// make a copy of the current block
|
||||
BasicBlock copy = (BasicBlock)child.clone();
|
||||
BasicBlock copy = child.clone();
|
||||
copy.id = ++last_id;
|
||||
// copy all successors
|
||||
if (copy.getLastInstruction().opcode == CodeConstants.opc_ret &&
|
||||
@ -682,14 +646,14 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
ExceptionRangeCFG range = exceptions.get(i);
|
||||
List<BasicBlock> lstRange = range.getProtectedRange();
|
||||
|
||||
HashSet<BasicBlock> setBoth = new HashSet<BasicBlock>(common_blocks);
|
||||
HashSet<BasicBlock> setBoth = new HashSet<>(common_blocks);
|
||||
setBoth.retainAll(lstRange);
|
||||
|
||||
if (setBoth.size() > 0) {
|
||||
List<BasicBlock> lstNewRange;
|
||||
|
||||
if (setBoth.size() == lstRange.size()) {
|
||||
lstNewRange = new ArrayList<BasicBlock>();
|
||||
lstNewRange = new ArrayList<>();
|
||||
ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange,
|
||||
mapNewNodes.get(range.getHandler().id), range.getExceptionTypes());
|
||||
exceptions.add(newRange);
|
||||
@ -705,8 +669,8 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeJsr(StructMethod mt) {
|
||||
removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
|
||||
private void removeJsr(StructClass cl, StructMethod mt) {
|
||||
removeJsrInstructions(cl.getPool(), first, DataPoint.getInitialDataPoint(mt));
|
||||
}
|
||||
|
||||
private static void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {
|
||||
@ -753,7 +717,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
if (suc.mark != 1) {
|
||||
|
||||
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));
|
||||
|
||||
removeJsrInstructions(pool, suc, point);
|
||||
@ -765,9 +729,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
first = blocks.get(0);
|
||||
|
||||
last = new BasicBlock();
|
||||
last.id = ++last_id;
|
||||
last.setSeq(new SimpleInstructionSequence());
|
||||
last = new BasicBlock(++last_id);
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
if (block.getSuccs().isEmpty()) {
|
||||
@ -778,18 +740,18 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
public List<BasicBlock> getReversePostOrder() {
|
||||
|
||||
List<BasicBlock> res = new LinkedList<BasicBlock>();
|
||||
List<BasicBlock> res = new LinkedList<>();
|
||||
addToReversePostOrderListIterative(first, 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<Integer> stackIndex = new LinkedList<Integer>();
|
||||
LinkedList<BasicBlock> stackNode = new LinkedList<>();
|
||||
LinkedList<Integer> stackIndex = new LinkedList<>();
|
||||
|
||||
Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
|
||||
Set<BasicBlock> setVisited = new HashSet<>();
|
||||
|
||||
stackNode.add(root);
|
||||
stackIndex.add(0);
|
||||
@ -801,7 +763,7 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
|
||||
setVisited.add(node);
|
||||
|
||||
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(node.getSuccs());
|
||||
List<BasicBlock> lstSuccs = new ArrayList<>(node.getSuccs());
|
||||
lstSuccs.addAll(node.getSuccExceptions());
|
||||
|
||||
for (; index < lstSuccs.size(); index++) {
|
||||
@ -834,10 +796,6 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public void setBlocks(VBStyleCollection<BasicBlock, Integer> blocks) {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public BasicBlock getFirst() {
|
||||
return first;
|
||||
}
|
||||
@ -846,39 +804,15 @@ public class ControlFlowGraph implements CodeConstants {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public List<BasicBlock> getEndBlocks() {
|
||||
return last.getPreds();
|
||||
}
|
||||
|
||||
public List<ExceptionRangeCFG> getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
public void setExceptions(List<ExceptionRangeCFG> exceptions) {
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
|
||||
public BasicBlock getLast() {
|
||||
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() {
|
||||
return finallyExits;
|
||||
}
|
||||
|
||||
public void setFinallyExits(HashSet<BasicBlock> finallyExits) {
|
||||
this.finallyExits = finallyExits;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +1,15 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.code.cfg;
|
||||
|
||||
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ExceptionRangeCFG {
|
||||
|
||||
private List<BasicBlock> protectedRange = new ArrayList<BasicBlock>(); // FIXME: replace with set
|
||||
|
||||
private final List<BasicBlock> protectedRange; // FIXME: replace with set
|
||||
private BasicBlock handler;
|
||||
|
||||
private List<String> exceptionTypes;
|
||||
|
||||
public ExceptionRangeCFG(List<BasicBlock> protectedRange, BasicBlock handler, List<String> exceptionType) {
|
||||
@ -35,7 +17,7 @@ public class ExceptionRangeCFG {
|
||||
this.handler = handler;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
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("handler: ").append(handler.id).append(new_line_separator);
|
||||
buf.append("range: ");
|
||||
for (int i = 0; i < protectedRange.size(); i++) {
|
||||
buf.append(protectedRange.get(i).id).append(" ");
|
||||
for (BasicBlock block : protectedRange) {
|
||||
buf.append(block.id).append(" ");
|
||||
}
|
||||
buf.append(new_line_separator);
|
||||
|
||||
@ -77,16 +65,11 @@ public class ExceptionRangeCFG {
|
||||
return protectedRange;
|
||||
}
|
||||
|
||||
public void setProtectedRange(List<BasicBlock> protectedRange) {
|
||||
this.protectedRange = protectedRange;
|
||||
}
|
||||
|
||||
public List<String> getExceptionTypes() {
|
||||
return this.exceptionTypes;
|
||||
}
|
||||
|
||||
public void addExceptionType(String exceptionType) {
|
||||
|
||||
if (this.exceptionTypes == null) {
|
||||
return;
|
||||
}
|
||||
@ -100,30 +83,6 @@ public class ExceptionRangeCFG {
|
||||
}
|
||||
|
||||
public String getUniqueExceptionsString() {
|
||||
|
||||
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;
|
||||
return exceptionTypes != null ? exceptionTypes.stream().distinct().collect(Collectors.joining(":")) : null;
|
||||
}
|
||||
|
||||
|
||||
// public void setExceptionType(String exceptionType) {
|
||||
// this.exceptionType = exceptionType;
|
||||
// }
|
||||
}
|
||||
}
|
@ -1,31 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.code.interpreter;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
import org.jetbrains.java.decompiler.code.Instruction;
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
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.gen.DataPoint;
|
||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||
import org.jetbrains.java.decompiler.util.ListStack;
|
||||
|
||||
public class InstructionImpact {
|
||||
public final class InstructionImpact {
|
||||
|
||||
// {read, write}
|
||||
private static final int[][][] stack_impact = {
|
||||
@ -338,7 +325,6 @@ public class InstructionImpact {
|
||||
|
||||
|
||||
public static void stepTypes(DataPoint data, Instruction instr, ConstantPool pool) {
|
||||
|
||||
ListStack<VarType> stack = data.getStack();
|
||||
int[][] arr = stack_impact[instr.opcode];
|
||||
|
||||
@ -350,8 +336,7 @@ public class InstructionImpact {
|
||||
|
||||
if (read != null) {
|
||||
int depth = 0;
|
||||
for (int i = 0; i < read.length; i++) {
|
||||
int type = read[i];
|
||||
for (int type : read) {
|
||||
depth++;
|
||||
if (type == CodeConstants.TYPE_LONG ||
|
||||
type == CodeConstants.TYPE_DOUBLE) {
|
||||
@ -363,8 +348,7 @@ public class InstructionImpact {
|
||||
}
|
||||
|
||||
if (write != null) {
|
||||
for (int i = 0; i < write.length; i++) {
|
||||
int type = write[i];
|
||||
for (int type : write) {
|
||||
stack.push(new VarType(type));
|
||||
if (type == CodeConstants.TYPE_LONG ||
|
||||
type == CodeConstants.TYPE_DOUBLE) {
|
||||
@ -394,8 +378,8 @@ public class InstructionImpact {
|
||||
case CodeConstants.opc_ldc:
|
||||
case CodeConstants.opc_ldc_w:
|
||||
case CodeConstants.opc_ldc2_w:
|
||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
||||
switch (cn.type) {
|
||||
PooledConstant constant = pool.getConstant(instr.operand(0));
|
||||
switch (constant.type) {
|
||||
case CodeConstants.CONSTANT_Integer:
|
||||
stack.push(new VarType(CodeConstants.TYPE_INT));
|
||||
break;
|
||||
@ -416,10 +400,13 @@ public class InstructionImpact {
|
||||
case CodeConstants.CONSTANT_Class:
|
||||
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class"));
|
||||
break;
|
||||
case CodeConstants.CONSTANT_MethodHandle:
|
||||
stack.push(new VarType(((LinkConstant)constant).descriptor));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CodeConstants.opc_aload:
|
||||
var1 = data.getVariable(instr.getOperand(0));
|
||||
var1 = data.getVariable(instr.operand(0));
|
||||
if (var1 != null) {
|
||||
stack.push(var1);
|
||||
}
|
||||
@ -429,10 +416,10 @@ public class InstructionImpact {
|
||||
break;
|
||||
case CodeConstants.opc_aaload:
|
||||
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;
|
||||
case CodeConstants.opc_astore:
|
||||
data.setVariable(instr.getOperand(0), stack.pop());
|
||||
data.setVariable(instr.operand(0), stack.pop());
|
||||
break;
|
||||
case CodeConstants.opc_dup:
|
||||
case CodeConstants.opc_dup_x1:
|
||||
@ -454,19 +441,19 @@ public class InstructionImpact {
|
||||
case CodeConstants.opc_getfield:
|
||||
stack.pop();
|
||||
case CodeConstants.opc_getstatic:
|
||||
ck = pool.getLinkConstant(instr.getOperand(0));
|
||||
ck = pool.getLinkConstant(instr.operand(0));
|
||||
var1 = new VarType(ck.descriptor);
|
||||
stack.push(var1);
|
||||
if (var1.stack_size == 2) {
|
||||
if (var1.stackSize == 2) {
|
||||
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
|
||||
}
|
||||
break;
|
||||
case CodeConstants.opc_putfield:
|
||||
stack.pop();
|
||||
case CodeConstants.opc_putstatic:
|
||||
ck = pool.getLinkConstant(instr.getOperand(0));
|
||||
ck = pool.getLinkConstant(instr.operand(0));
|
||||
var1 = new VarType(ck.descriptor);
|
||||
stack.pop(var1.stack_size);
|
||||
stack.pop(var1.stackSize);
|
||||
break;
|
||||
case CodeConstants.opc_invokevirtual:
|
||||
case CodeConstants.opc_invokespecial:
|
||||
@ -474,29 +461,27 @@ public class InstructionImpact {
|
||||
stack.pop();
|
||||
case CodeConstants.opc_invokestatic:
|
||||
case CodeConstants.opc_invokedynamic:
|
||||
if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
|
||||
ck = pool.getLinkConstant(instr.getOperand(0));
|
||||
if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) {
|
||||
ck = pool.getLinkConstant(instr.operand(0));
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
|
||||
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) {
|
||||
stack.push(md.ret);
|
||||
if (md.ret.stack_size == 2) {
|
||||
if (md.ret.stackSize == 2) {
|
||||
stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
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()));
|
||||
break;
|
||||
case CodeConstants.opc_newarray:
|
||||
stack.pop();
|
||||
var1 = new VarType(arr_type[instr.getOperand(0) - 4]);
|
||||
var1.arraydim = 1;
|
||||
stack.push(var1);
|
||||
stack.push(new VarType(arr_type[instr.operand(0) - 4], 1).resizeArrayDim(1));
|
||||
break;
|
||||
case CodeConstants.opc_athrow:
|
||||
var1 = stack.pop();
|
||||
@ -506,17 +491,17 @@ public class InstructionImpact {
|
||||
case CodeConstants.opc_checkcast:
|
||||
case CodeConstants.opc_instanceof:
|
||||
stack.pop();
|
||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
||||
cn = pool.getPrimitiveConstant(instr.operand(0));
|
||||
stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
|
||||
break;
|
||||
case CodeConstants.opc_anewarray:
|
||||
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);
|
||||
cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
||||
cn = pool.getPrimitiveConstant(instr.operand(0));
|
||||
if (cn.isArray) {
|
||||
var1 = new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString());
|
||||
var1.arraydim += dimensions;
|
||||
var1 = var1.resizeArrayDim(var1.arrayDim + dimensions);
|
||||
stack.push(var1);
|
||||
}
|
||||
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-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.
|
||||
*/
|
||||
// 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.main;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
@ -35,13 +21,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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");
|
||||
|
||||
public static void buildAssertions(ClassNode node) {
|
||||
|
||||
ClassWrapper wrapper = node.wrapper;
|
||||
ClassWrapper wrapper = node.getWrapper();
|
||||
|
||||
StructField field = findAssertionField(node);
|
||||
|
||||
@ -67,7 +53,7 @@ public class AssertProcessor {
|
||||
|
||||
private static StructField findAssertionField(ClassNode node) {
|
||||
|
||||
ClassWrapper wrapper = node.wrapper;
|
||||
ClassWrapper wrapper = node.getWrapper();
|
||||
|
||||
boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
|
||||
|
||||
@ -89,7 +75,7 @@ public class AssertProcessor {
|
||||
if (initializer.type == Exprent.EXPRENT_FUNCTION) {
|
||||
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) {
|
||||
|
||||
InvocationExprent invexpr = (InvocationExprent)fexpr.getLstOperands().get(0);
|
||||
@ -101,11 +87,11 @@ public class AssertProcessor {
|
||||
invexpr.getLstParameters().isEmpty()) {
|
||||
|
||||
ConstExprent cexpr = (ConstExprent)invexpr.getInstance();
|
||||
if (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype())) {
|
||||
if (VarType.VARTYPE_CLASS.equals(cexpr.getConstType())) {
|
||||
|
||||
ClassNode nd = node;
|
||||
while (nd != null) {
|
||||
if (nd.wrapper.getClassStruct().qualifiedName.equals(cexpr.getValue())) {
|
||||
if (nd.getWrapper().getClassStruct().qualifiedName.equals(cexpr.getValue())) {
|
||||
break;
|
||||
}
|
||||
nd = nd.parent;
|
||||
@ -157,26 +143,42 @@ public class AssertProcessor {
|
||||
|
||||
private static boolean replaceAssertion(Statement parent, IfStatement stat, String classname, String key) {
|
||||
|
||||
boolean throwInIf = true;
|
||||
Statement ifstat = stat.getIfstat();
|
||||
InvocationExprent throwError = isAssertionError(ifstat);
|
||||
|
||||
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]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Exprent> lstParams = new ArrayList<Exprent>();
|
||||
List<Exprent> lstParams = new ArrayList<>();
|
||||
|
||||
Exprent ascond = null, retcond = null;
|
||||
if (exprres[0] != null) {
|
||||
ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
|
||||
Arrays.asList(new Exprent[]{(Exprent)exprres[0]}));
|
||||
retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
|
||||
if (throwInIf) {
|
||||
if (exprres[0] != null) {
|
||||
ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, (Exprent)exprres[0], throwError.bytecode);
|
||||
retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ascond = (Exprent) exprres[0];
|
||||
retcond = ascond;
|
||||
}
|
||||
|
||||
|
||||
lstParams.add(retcond == null ? ascond : retcond);
|
||||
if (!throwError.getLstParameters().isEmpty()) {
|
||||
@ -197,13 +199,18 @@ public class AssertProcessor {
|
||||
first.removeSuccessor(stat.getIfEdge());
|
||||
first.removeSuccessor(stat.getElseEdge());
|
||||
|
||||
List<Statement> lstStatements = new ArrayList<Statement>();
|
||||
List<Statement> lstStatements = new ArrayList<>();
|
||||
if (first.getExprents() != null && !first.getExprents().isEmpty()) {
|
||||
lstStatements.add(first);
|
||||
}
|
||||
lstStatements.add(newstat);
|
||||
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);
|
||||
@ -214,10 +221,16 @@ public class AssertProcessor {
|
||||
sequence.getStats().get(i), sequence.getStats().get(i + 1)));
|
||||
}
|
||||
|
||||
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||
Statement ifelse = stat.getElsestat();
|
||||
if (stat.iftype == IfStatement.IFTYPE_IFELSE || !throwInIf) {
|
||||
Statement stmts;
|
||||
if (throwInIf) {
|
||||
stmts = stat.getElsestat();
|
||||
}
|
||||
else {
|
||||
stmts = stat.getIfstat();
|
||||
}
|
||||
|
||||
List<StatEdge> lstSuccs = ifelse.getAllSuccessorEdges();
|
||||
List<StatEdge> lstSuccs = stmts.getAllSuccessorEdges();
|
||||
if (!lstSuccs.isEmpty()) {
|
||||
StatEdge endedge = lstSuccs.get(0);
|
||||
if (endedge.closure == stat) {
|
||||
@ -245,9 +258,9 @@ public class AssertProcessor {
|
||||
|
||||
if (expr.type == Exprent.EXPRENT_EXIT) {
|
||||
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();
|
||||
if (CLASS_ASSERTION_ERROR.equals(nexpr.getNewtype()) && nexpr.getConstructor() != null) {
|
||||
if (CLASS_ASSERTION_ERROR.equals(nexpr.getNewType()) && nexpr.getConstructor() != null) {
|
||||
return nexpr.getConstructor();
|
||||
}
|
||||
}
|
||||
@ -256,16 +269,21 @@ public class AssertProcessor {
|
||||
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) {
|
||||
int desiredOperation = FunctionExprent.FUNCTION_CADD;
|
||||
if (!throwInIf) {
|
||||
desiredOperation = FunctionExprent.FUNCTION_COR;
|
||||
}
|
||||
|
||||
FunctionExprent fexpr = (FunctionExprent)exprent;
|
||||
if (fexpr.getFunctype() == FunctionExprent.FUNCTION_CADD) {
|
||||
if (fexpr.getFuncType() == desiredOperation) {
|
||||
|
||||
for (int i = 0; i < 2; 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};
|
||||
}
|
||||
}
|
||||
@ -273,7 +291,7 @@ public class AssertProcessor {
|
||||
for (int i = 0; i < 2; 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 (param != 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;
|
||||
return new Object[]{null, true};
|
||||
}
|
||||
@ -291,20 +309,25 @@ public class AssertProcessor {
|
||||
return new Object[]{exprent, false};
|
||||
}
|
||||
|
||||
private static boolean isAssertionField(Exprent exprent, String classname, String key) {
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
||||
FunctionExprent fparam = (FunctionExprent)exprent;
|
||||
if (fparam.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
|
||||
fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
|
||||
FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
|
||||
if (classname.equals(fdparam.getClassname())
|
||||
&& key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString))) {
|
||||
return true;
|
||||
private static boolean isAssertionField(Exprent exprent, String classname, String key, boolean throwInIf) {
|
||||
if (throwInIf) {
|
||||
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
||||
FunctionExprent fparam = (FunctionExprent)exprent;
|
||||
if (fparam.getFuncType() == FunctionExprent.FUNCTION_BOOL_NOT &&
|
||||
fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
|
||||
FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
|
||||
return classname.equals(fdparam.getClassname()) &&
|
||||
key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.main;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
@ -36,79 +22,48 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
import java.util.*;
|
||||
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;
|
||||
|
||||
|
||||
public ClassReference14Processor() {
|
||||
|
||||
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(Arrays.asList(new Exprent[]{new VarExprent(0, VarType.VARTYPE_STRING, null)}));
|
||||
|
||||
bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN,
|
||||
invfor,
|
||||
VarType.VARTYPE_CLASS);
|
||||
|
||||
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);
|
||||
InvocationExprent ctor = new InvocationExprent();
|
||||
ctor.setName(CodeConstants.INIT_NAME);
|
||||
ctor.setClassname("java/lang/NoClassDefFoundError");
|
||||
ctor.setStringDescriptor("()V");
|
||||
ctor.setFunctype(InvocationExprent.TYP_INIT);
|
||||
ctor.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
|
||||
NewExprent newExpr = new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<>(), null);
|
||||
newExpr.setConstructor(ctor);
|
||||
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(
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static void processClassReferences(ClassNode node) {
|
||||
// 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);
|
||||
|
||||
if (mapClassMeths.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<ClassWrapper> setFound = new HashSet<ClassWrapper>();
|
||||
Set<ClassWrapper> setFound = new HashSet<>();
|
||||
processClassRec(node, mapClassMeths, setFound);
|
||||
|
||||
if (!setFound.isEmpty()) {
|
||||
@ -119,29 +74,21 @@ public class ClassReference14Processor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void processClassRec(ClassNode node,
|
||||
final HashMap<ClassWrapper, MethodWrapper> mapClassMeths,
|
||||
final HashSet<ClassWrapper> setFound) {
|
||||
|
||||
final ClassWrapper wrapper = node.wrapper;
|
||||
private static void processClassRec(ClassNode node, Map<ClassWrapper, MethodWrapper> mapClassMeths, Set<? super ClassWrapper> setFound) {
|
||||
ClassWrapper wrapper = node.getWrapper();
|
||||
|
||||
// search code
|
||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
||||
|
||||
RootStatement root = meth.root;
|
||||
if (root != null) {
|
||||
|
||||
DirectGraph graph = meth.getOrBuildGraph();
|
||||
|
||||
graph.iterateExprents(new DirectGraph.ExprentIterator() {
|
||||
public int processExprent(Exprent exprent) {
|
||||
for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
|
||||
if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
|
||||
setFound.add(ent.getKey());
|
||||
}
|
||||
graph.iterateExprents(exprent -> {
|
||||
for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
|
||||
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());
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
ClassWrapper wrapper = node.wrapper;
|
||||
ClassWrapper wrapper = node.getWrapper();
|
||||
|
||||
for (MethodWrapper method : wrapper.getMethods()) {
|
||||
StructMethod mt = method.methodStruct;
|
||||
@ -190,14 +137,14 @@ public class ClassReference14Processor {
|
||||
CatchStatement cst = (CatchStatement)root.getFirst();
|
||||
if (cst.getStats().size() == 2 && cst.getFirst().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 handler = (BasicBlockStatement)cst.getStats().get(1);
|
||||
|
||||
if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
|
||||
if (bodyexprent.equals(body.getExprents().get(0)) &&
|
||||
handlerexprent.equals(handler.getExprents().get(0))) {
|
||||
if (BODY_EXPR.equals(body.getExprents().get(0)) &&
|
||||
HANDLER_EXPR.equals(handler.getExprents().get(0))) {
|
||||
map.put(wrapper, method);
|
||||
break;
|
||||
}
|
||||
@ -213,19 +160,16 @@ public class ClassReference14Processor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
|
||||
|
||||
boolean res = false;
|
||||
|
||||
while (true) {
|
||||
|
||||
boolean found = false;
|
||||
|
||||
for (Exprent expr : exprent.getAllExprents()) {
|
||||
String cl = isClass14Invocation(expr, wrapper, meth);
|
||||
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;
|
||||
res = true;
|
||||
break;
|
||||
@ -242,18 +186,16 @@ public class ClassReference14Processor {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
|
||||
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) {
|
||||
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 &&
|
||||
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);
|
||||
ClassNode fieldnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(field.getClassname());
|
||||
@ -293,4 +235,4 @@ public class ClassReference14Processor {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,10 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main;
|
||||
|
||||
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.CounterContainer;
|
||||
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
|
||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||
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.NestedMemberAccess;
|
||||
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.StructContext;
|
||||
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.consts.ConstantPool;
|
||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
import org.jetbrains.java.decompiler.util.TextBuffer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class ClassesProcessor {
|
||||
|
||||
public class ClassesProcessor implements CodeConstants {
|
||||
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) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
HashMap<String, Object[]> mapInnerClasses = new HashMap<String, Object[]>();
|
||||
HashMap<String, HashSet<String>> mapNestedClassReferences = new HashMap<String, HashSet<String>>();
|
||||
HashMap<String, HashSet<String>> mapEnclosingClassReferences = new HashMap<String, HashSet<String>>();
|
||||
HashMap<String, String> mapNewSimpleNames = new HashMap<String, String>();
|
||||
public void loadClasses(IIdentifierRenamer renamer) {
|
||||
Map<String, Inner> mapInnerClasses = new HashMap<>();
|
||||
Map<String, Set<String>> mapNestedClassReferences = new HashMap<>();
|
||||
Map<String, Set<String>> mapEnclosingClassReferences = new HashMap<>();
|
||||
Map<String, String> mapNewSimpleNames = new HashMap<>();
|
||||
|
||||
boolean bDecompileInner = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_INNER);
|
||||
boolean verifyAnonymousClasses = DecompilerContext.getOption(IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES);
|
||||
|
||||
// create class nodes
|
||||
for (StructClass cl : context.getClasses().values()) {
|
||||
if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
|
||||
|
||||
if (bDecompileInner) {
|
||||
StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses");
|
||||
StructInnerClassesAttribute inner = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES);
|
||||
|
||||
if (inner != null) {
|
||||
|
||||
for (int i = 0; i < inner.getClassEntries().size(); i++) {
|
||||
|
||||
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;
|
||||
for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) {
|
||||
String innerName = entry.innerName;
|
||||
|
||||
// original simple name
|
||||
String simpleName = strentry[2];
|
||||
String savedName = mapNewSimpleNames.get(innername);
|
||||
|
||||
String simpleName = entry.simpleName;
|
||||
String savedName = mapNewSimpleNames.get(innerName);
|
||||
if (savedName != null) {
|
||||
simpleName = savedName;
|
||||
}
|
||||
else if (simpleName != null && DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
|
||||
IIdentifierRenamer renamer = DecompilerContext.getPoolInterceptor().getHelper();
|
||||
if (renamer.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, simpleName, null, null)) {
|
||||
simpleName = renamer.getNextClassname(innername, simpleName);
|
||||
mapNewSimpleNames.put(innername, simpleName);
|
||||
}
|
||||
else if (simpleName != null &&
|
||||
renamer != null &&
|
||||
renamer.toBeRenamed(IIdentifierRenamer.Type.ELEMENT_CLASS, simpleName, null, null)) {
|
||||
simpleName = renamer.getNextClassName(innerName, simpleName);
|
||||
mapNewSimpleNames.put(innerName, simpleName);
|
||||
}
|
||||
|
||||
arr[1] = simpleName;
|
||||
|
||||
// original access flags
|
||||
arr[3] = entry[3];
|
||||
Inner rec = new Inner();
|
||||
rec.simpleName = simpleName;
|
||||
rec.type = entry.simpleNameIdx == 0 ? ClassNode.CLASS_ANONYMOUS : entry.outerNameIdx == 0 ? ClassNode.CLASS_LOCAL : ClassNode.CLASS_MEMBER;
|
||||
rec.accessFlags = entry.accessFlags;
|
||||
|
||||
// enclosing class
|
||||
String enclClassName;
|
||||
if (entry[1] != 0) {
|
||||
enclClassName = strentry[1];
|
||||
String enclClassName = entry.outerNameIdx != 0 ? entry.enclosingName : cl.qualifiedName;
|
||||
if (enclClassName == null || innerName.equals(enclClassName)) {
|
||||
continue; // invalid name or self reference
|
||||
}
|
||||
else {
|
||||
enclClassName = cl.qualifiedName;
|
||||
if (rec.type == ClassNode.CLASS_MEMBER && !innerName.equals(enclClassName + '$' + entry.simpleName)) {
|
||||
continue; // not a real inner class
|
||||
}
|
||||
|
||||
if (!innername.equals(enclClassName)) { // self reference
|
||||
StructClass enclosing_class = context.getClasses().get(enclClassName);
|
||||
if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only
|
||||
|
||||
Object[] arrold = mapInnerClasses.get(innername);
|
||||
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);
|
||||
StructClass enclosingClass = context.getClasses().get(enclClassName);
|
||||
if (enclosingClass != null && enclosingClass.isOwn()) { // own classes only
|
||||
Inner existingRec = mapInnerClasses.get(innerName);
|
||||
if (existingRec == null) {
|
||||
mapInnerClasses.put(innerName, rec);
|
||||
}
|
||||
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) {
|
||||
|
||||
// connect nested classes
|
||||
for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) {
|
||||
// root class?
|
||||
if (!mapInnerClasses.containsKey(ent.getKey())) {
|
||||
|
||||
HashSet<String> setVisited = new HashSet<String>();
|
||||
LinkedList<String> stack = new LinkedList<String>();
|
||||
Set<String> setVisited = new HashSet<>();
|
||||
LinkedList<String> stack = new LinkedList<>();
|
||||
|
||||
stack.add(ent.getKey());
|
||||
setVisited.add(ent.getKey());
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
|
||||
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) {
|
||||
StructClass scl = superNode.classStruct;
|
||||
StructInnerClassesAttribute inner = scl.getAttribute(StructGeneralAttribute.ATTRIBUTE_INNER_CLASSES);
|
||||
|
||||
StructClass scl = supernode.classStruct;
|
||||
StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses");
|
||||
for (int i = 0; i < inner.getStringEntries().size(); i++) {
|
||||
String nestedClass = inner.getStringEntries().get(i)[0];
|
||||
if (inner == null || inner.getEntries().isEmpty()) {
|
||||
DecompilerContext.getLogger().writeMessage(superClass + " does not contain inner classes!", IFernflowerLogger.Severity.WARN);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) {
|
||||
String nestedClass = entry.innerName;
|
||||
if (!setNestedClasses.contains(nestedClass)) {
|
||||
continue;
|
||||
}
|
||||
@ -174,52 +157,49 @@ public class ClassesProcessor {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClassNode nestednode = mapRootClasses.get(nestedClass);
|
||||
if (nestednode == null) {
|
||||
ClassNode nestedNode = mapRootClasses.get(nestedClass);
|
||||
if (nestedNode == null) {
|
||||
DecompilerContext.getLogger().writeMessage("Nested class " + nestedClass + " missing!", IFernflowerLogger.Severity.WARN);
|
||||
continue;
|
||||
}
|
||||
|
||||
Object[] arr = mapInnerClasses.get(nestedClass);
|
||||
Inner rec = mapInnerClasses.get(nestedClass);
|
||||
|
||||
//if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
|
||||
// FIXME: check for consistent naming
|
||||
//}
|
||||
|
||||
nestednode.type = (Integer)arr[2];
|
||||
nestednode.simpleName = (String)arr[1];
|
||||
nestednode.access = (Integer)arr[3];
|
||||
nestedNode.simpleName = rec.simpleName;
|
||||
nestedNode.type = rec.type;
|
||||
nestedNode.access = rec.accessFlags;
|
||||
|
||||
if (nestednode.type == ClassNode.CLASS_ANONYMOUS) {
|
||||
StructClass cl = nestednode.classStruct;
|
||||
// sanity checks of the class supposed to be anonymous
|
||||
if (verifyAnonymousClasses && nestedNode.type == ClassNode.CLASS_ANONYMOUS && !isAnonymous(nestedNode.classStruct, scl)) {
|
||||
nestedNode.type = ClassNode.CLASS_LOCAL;
|
||||
}
|
||||
|
||||
// remove static if anonymous class
|
||||
// a common compiler bug
|
||||
nestednode.access &= ~CodeConstants.ACC_STATIC;
|
||||
if (nestedNode.type == ClassNode.CLASS_ANONYMOUS) {
|
||||
StructClass cl = nestedNode.classStruct;
|
||||
// remove static if anonymous class (a common compiler bug)
|
||||
nestedNode.access &= ~CodeConstants.ACC_STATIC;
|
||||
|
||||
int[] interfaces = cl.getInterfaces();
|
||||
|
||||
if (interfaces.length > 0) {
|
||||
if (interfaces.length > 1) {
|
||||
String message = "Inconsistent anonymous class definition: " + cl.qualifiedName;
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||
}
|
||||
nestednode.anonymousClassType = new VarType(cl.getInterface(0), true);
|
||||
nestedNode.anonymousClassType = new VarType(cl.getInterface(0), true);
|
||||
}
|
||||
else {
|
||||
nestednode.anonymousClassType = new VarType(cl.superClass.getString(), true);
|
||||
nestedNode.anonymousClassType = new VarType(cl.superClass.getString(), true);
|
||||
}
|
||||
}
|
||||
else if (nestednode.type == ClassNode.CLASS_LOCAL) {
|
||||
// only abstract and final are permitted
|
||||
// a common compiler bug
|
||||
nestednode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
|
||||
else if (nestedNode.type == ClassNode.CLASS_LOCAL) {
|
||||
// only abstract and final are permitted (a common compiler bug)
|
||||
nestedNode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
|
||||
}
|
||||
|
||||
supernode.nested.add(nestednode);
|
||||
nestednode.parent = supernode;
|
||||
superNode.nested.add(nestedNode);
|
||||
nestedNode.parent = superNode;
|
||||
|
||||
nestednode.enclosingClasses.addAll(mapEnclosingClassReferences.get(nestedClass));
|
||||
nestedNode.enclosingClasses.addAll(mapEnclosingClassReferences.get(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 {
|
||||
ClassNode root = mapRootClasses.get(cl.qualifiedName);
|
||||
if (root.type != ClassNode.CLASS_ROOT) {
|
||||
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);
|
||||
try {
|
||||
ImportCollector importCollector = new ImportCollector(root);
|
||||
DecompilerContext.setImportCollector(importCollector);
|
||||
DecompilerContext.setCounterContainer(new CounterContainer());
|
||||
DecompilerContext.setBytecodeSourceMapper(new BytecodeSourceMapper());
|
||||
DecompilerContext.startClass(importCollector);
|
||||
|
||||
new LambdaProcessor().processClass(root);
|
||||
if (packageInfo) {
|
||||
ClassWriter.packageInfoToJava(cl, buffer);
|
||||
|
||||
// add simple class names to implicit import
|
||||
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);
|
||||
importCollector.writeImports(buffer, false);
|
||||
}
|
||||
else if (moduleInfo) {
|
||||
TextBuffer moduleBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
|
||||
ClassWriter.moduleInfoToJava(cl, moduleBuffer);
|
||||
|
||||
int import_lines_written = importCollector.writeImports(buffer);
|
||||
if (import_lines_written > 0) {
|
||||
buffer.append(lineSeparator);
|
||||
total_offset_lines += import_lines_written + 1;
|
||||
importCollector.writeImports(buffer, true);
|
||||
|
||||
buffer.append(moduleBuffer);
|
||||
}
|
||||
//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)) {
|
||||
BytecodeSourceMapper mapper = DecompilerContext.getBytecodeSourceMapper();
|
||||
mapper.addTotalOffset(total_offset_lines);
|
||||
// build wrappers for all nested classes (that's where actual processing takes place)
|
||||
initWrappers(root);
|
||||
|
||||
buffer.append(lineSeparator);
|
||||
mapper.dumpMapping(buffer);
|
||||
new NestedClassProcessor().processClass(root, root);
|
||||
|
||||
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 {
|
||||
@ -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) {
|
||||
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) {
|
||||
imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false);
|
||||
}
|
||||
|
||||
for (ClassNode nd : node.nested) {
|
||||
addClassnameToImport(nd, imp);
|
||||
addClassNameToImport(nd, imp);
|
||||
}
|
||||
}
|
||||
|
||||
private static void destroyWrappers(ClassNode node) {
|
||||
|
||||
node.wrapper = null;
|
||||
node.classStruct.releaseResources();
|
||||
|
||||
@ -339,7 +410,6 @@ public class ClassesProcessor {
|
||||
|
||||
|
||||
public static class ClassNode {
|
||||
|
||||
public static final int CLASS_ROOT = 0;
|
||||
public static final int CLASS_MEMBER = 1;
|
||||
public static final int CLASS_ANONYMOUS = 2;
|
||||
@ -347,30 +417,18 @@ public class ClassesProcessor {
|
||||
public static final int CLASS_LAMBDA = 8;
|
||||
|
||||
public int type;
|
||||
|
||||
public int access;
|
||||
|
||||
public String simpleName;
|
||||
|
||||
public StructClass classStruct;
|
||||
|
||||
public ClassWrapper wrapper;
|
||||
|
||||
public final StructClass classStruct;
|
||||
private ClassWrapper wrapper;
|
||||
public String enclosingMethod;
|
||||
|
||||
public InvocationExprent superInvocation;
|
||||
|
||||
public HashMap<String, VarVersionPaar> mapFieldsToVars = new HashMap<String, VarVersionPaar>();
|
||||
|
||||
public final Map<String, VarVersionPair> mapFieldsToVars = new HashMap<>();
|
||||
public VarType anonymousClassType;
|
||||
|
||||
public List<ClassNode> nested = new ArrayList<ClassNode>();
|
||||
|
||||
public Set<String> enclosingClasses = new HashSet<String>();
|
||||
|
||||
public final List<ClassNode> nested = new ArrayList<>();
|
||||
public final Set<String> enclosingClasses = new HashSet<>();
|
||||
public ClassNode parent;
|
||||
|
||||
public LambdaInformation lambda_information;
|
||||
public LambdaInformation lambdaInformation;
|
||||
|
||||
public ClassNode(String content_class_name,
|
||||
String content_method_name,
|
||||
@ -383,19 +441,18 @@ public class ClassesProcessor {
|
||||
this.type = CLASS_LAMBDA;
|
||||
this.classStruct = classStruct; // 'parent' class containing the static function
|
||||
|
||||
lambda_information = new LambdaInformation();
|
||||
lambdaInformation = new LambdaInformation();
|
||||
|
||||
lambda_information.class_name = lambda_class_name;
|
||||
lambda_information.method_name = lambda_method_name;
|
||||
lambda_information.method_descriptor = lambda_method_descriptor;
|
||||
lambdaInformation.method_name = lambda_method_name;
|
||||
lambdaInformation.method_descriptor = lambda_method_descriptor;
|
||||
|
||||
lambda_information.content_class_name = content_class_name;
|
||||
lambda_information.content_method_name = content_method_name;
|
||||
lambda_information.content_method_descriptor = content_method_descriptor;
|
||||
lambda_information.content_method_invocation_type = content_method_invocation_type;
|
||||
lambdaInformation.content_class_name = content_class_name;
|
||||
lambdaInformation.content_method_name = content_method_name;
|
||||
lambdaInformation.content_method_descriptor = content_method_descriptor;
|
||||
lambdaInformation.content_method_invocation_type = content_method_invocation_type;
|
||||
|
||||
lambda_information.content_method_key =
|
||||
InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
|
||||
lambdaInformation.content_method_key =
|
||||
InterpreterUtil.makeUniqueKey(lambdaInformation.content_method_name, lambdaInformation.content_method_descriptor);
|
||||
|
||||
anonymousClassType = new VarType(lambda_class_name, true);
|
||||
|
||||
@ -405,9 +462,9 @@ public class ClassesProcessor {
|
||||
is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference
|
||||
}
|
||||
|
||||
lambda_information.is_method_reference = is_method_reference;
|
||||
lambda_information.is_content_method_static =
|
||||
(lambda_information.content_method_invocation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
|
||||
lambdaInformation.is_method_reference = is_method_reference;
|
||||
lambdaInformation.is_content_method_static =
|
||||
(lambdaInformation.content_method_invocation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
|
||||
}
|
||||
|
||||
public ClassNode(int type, StructClass classStruct) {
|
||||
@ -426,8 +483,15 @@ public class ClassesProcessor {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ClassWrapper getWrapper() {
|
||||
ClassNode node = this;
|
||||
while (node.type == CLASS_LAMBDA) {
|
||||
node = node.parent;
|
||||
}
|
||||
return node.wrapper;
|
||||
}
|
||||
|
||||
public static class LambdaInformation {
|
||||
public String class_name;
|
||||
public String method_name;
|
||||
public String method_descriptor;
|
||||
|
||||
@ -435,11 +499,10 @@ public class ClassesProcessor {
|
||||
public String content_method_name;
|
||||
public String content_method_descriptor;
|
||||
public int content_method_invocation_type; // values from CONSTANT_MethodHandle_REF_*
|
||||
|
||||
public String content_method_key;
|
||||
|
||||
public boolean is_method_reference;
|
||||
public boolean is_content_method_static;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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;
|
||||
|
||||
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.VarNamesCollector;
|
||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||
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.struct.StructContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DecompilerContext {
|
||||
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_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_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR";
|
||||
|
||||
private static ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<DecompilerContext>();
|
||||
|
||||
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 VarNamesCollector varNamescollector;
|
||||
private VarProcessor varProcessor;
|
||||
private CounterContainer counterContainer;
|
||||
private ClassesProcessor classProcessor;
|
||||
private PoolInterceptor poolInterceptor;
|
||||
private IFernflowerLogger logger;
|
||||
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.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);
|
||||
if (propertiesCustom != null) {
|
||||
properties.putAll(propertiesCustom);
|
||||
}
|
||||
currentContext.set(new DecompilerContext(properties));
|
||||
}
|
||||
// *****************************************************************************
|
||||
// context setup and update
|
||||
// *****************************************************************************
|
||||
|
||||
private static final ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<>();
|
||||
|
||||
public static DecompilerContext getCurrentContext() {
|
||||
return currentContext.get();
|
||||
@ -68,93 +61,69 @@ public class DecompilerContext {
|
||||
currentContext.set(context);
|
||||
}
|
||||
|
||||
public static Object getProperty(String key) {
|
||||
return getCurrentContext().properties.get(key);
|
||||
}
|
||||
|
||||
public static void setProperty(String key, Object 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) {
|
||||
return "1".equals(getCurrentContext().properties.get(key));
|
||||
return "1".equals(getProperty(key));
|
||||
}
|
||||
|
||||
public static ImportCollector getImportCollector() {
|
||||
return getCurrentContext().importCollector;
|
||||
}
|
||||
|
||||
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 String getNewLineSeparator() {
|
||||
return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
|
||||
IFernflowerPreferences.LINE_SEPARATOR_UNX : IFernflowerPreferences.LINE_SEPARATOR_WIN;
|
||||
}
|
||||
|
||||
public static IFernflowerLogger getLogger() {
|
||||
return getCurrentContext().logger;
|
||||
}
|
||||
|
||||
public static void setLogger(IFernflowerLogger logger) {
|
||||
if (logger != null) {
|
||||
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 StructContext getStructContext() {
|
||||
return getCurrentContext().structContext;
|
||||
}
|
||||
|
||||
public static String getNewLineSeparator() {
|
||||
return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
|
||||
IFernflowerPreferences.LINE_SEPARATOR_LIN : IFernflowerPreferences.LINE_SEPARATOR_WIN;
|
||||
public static ClassesProcessor getClassProcessor() {
|
||||
return getCurrentContext().classProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
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-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.
|
||||
*/
|
||||
// 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.main;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
|
||||
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.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.vars.VarVersionPaar;
|
||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statements;
|
||||
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.util.InterpreterUtil;
|
||||
|
||||
public class EnumProcessor {
|
||||
|
||||
public final class EnumProcessor {
|
||||
public static void clearEnum(ClassWrapper wrapper) {
|
||||
StructClass cl = wrapper.getClassStruct();
|
||||
|
||||
@ -48,13 +33,13 @@ public class EnumProcessor {
|
||||
wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, descriptor));
|
||||
}
|
||||
}
|
||||
else if ("<init>".equals(name)) {
|
||||
Statement firstData = findFirstData(method.root);
|
||||
else if (CodeConstants.INIT_NAME.equals(name)) {
|
||||
Statement firstData = Statements.findFirstData(method.root);
|
||||
if (firstData != null && !firstData.getExprents().isEmpty()) {
|
||||
Exprent exprent = firstData.getExprents().get(0);
|
||||
if (exprent.type == Exprent.EXPRENT_INVOCATION) {
|
||||
InvocationExprent invexpr = (InvocationExprent)exprent;
|
||||
if (isInvocationSuperConstructor(invexpr, method, wrapper)) {
|
||||
InvocationExprent invExpr = (InvocationExprent)exprent;
|
||||
if (Statements.isInvocationInitConstructor(invExpr, method, wrapper, false)) {
|
||||
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-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.
|
||||
*/
|
||||
// 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;
|
||||
|
||||
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
|
||||
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
|
||||
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
|
||||
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.main.extern.*;
|
||||
import org.jetbrains.java.decompiler.modules.renamer.ConverterHelper;
|
||||
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.StructClass;
|
||||
import org.jetbrains.java.decompiler.struct.StructContext;
|
||||
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;
|
||||
|
||||
public class Fernflower implements IDecompiledData {
|
||||
private final StructContext structContext;
|
||||
private final ClassesProcessor classProcessor;
|
||||
private final IIdentifierRenamer helper;
|
||||
private final IdentifierConverter converter;
|
||||
|
||||
private StructContext structContext;
|
||||
private ClassesProcessor classesProcessor;
|
||||
public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> customProperties, IFernflowerLogger logger) {
|
||||
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));
|
||||
DecompilerContext.initContext(options);
|
||||
DecompilerContext.setCounterContainer(new CounterContainer());
|
||||
DecompilerContext.setLogger(logger);
|
||||
classProcessor = new ClassesProcessor(structContext);
|
||||
|
||||
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() {
|
||||
if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
|
||||
new IdentifierConverter().rename(structContext);
|
||||
if (converter != null) {
|
||||
converter.rename();
|
||||
}
|
||||
|
||||
classesProcessor = new ClassesProcessor(structContext);
|
||||
|
||||
DecompilerContext.setClassProcessor(classesProcessor);
|
||||
DecompilerContext.setStructContext(structContext);
|
||||
classProcessor.loadClasses(helper);
|
||||
|
||||
structContext.saveContext();
|
||||
}
|
||||
@ -58,24 +91,18 @@ public class Fernflower implements IDecompiledData {
|
||||
DecompilerContext.setCurrentContext(null);
|
||||
}
|
||||
|
||||
public StructContext getStructContext() {
|
||||
return structContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
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 {
|
||||
if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
|
||||
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";
|
||||
}
|
||||
return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java";
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,12 +111,12 @@ public class Fernflower implements IDecompiledData {
|
||||
try {
|
||||
TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);
|
||||
buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString());
|
||||
classesProcessor.writeClass(cl, buffer);
|
||||
return org.spigotmc.fernflower.EclipseFormatter.format(buffer.toString()); // Spigot
|
||||
classProcessor.writeClass(cl, buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex);
|
||||
catch (Throwable t) {
|
||||
DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.main;
|
||||
|
||||
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.stats.RootStatement;
|
||||
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.StructField;
|
||||
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.List;
|
||||
|
||||
|
||||
public class InitializerProcessor {
|
||||
|
||||
public final class InitializerProcessor {
|
||||
public static void extractInitializers(ClassWrapper wrapper) {
|
||||
|
||||
MethodWrapper meth = wrapper.getMethodWrapper("<clinit>", "()V");
|
||||
if (meth != null && meth.root != null) { // successfully decompiled static constructor
|
||||
extractStaticInitializers(wrapper, meth);
|
||||
MethodWrapper method = wrapper.getMethodWrapper(CodeConstants.CLINIT_NAME, "()V");
|
||||
if (method != null && method.root != null) { // successfully decompiled static constructor
|
||||
extractStaticInitializers(wrapper, method);
|
||||
}
|
||||
|
||||
extractDynamicInitializers(wrapper);
|
||||
@ -52,30 +36,26 @@ public class InitializerProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void liftConstructor(ClassWrapper wrapper) {
|
||||
|
||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
||||
if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
|
||||
Statement firstdata = findFirstData(meth.root);
|
||||
if (firstdata == null) {
|
||||
for (MethodWrapper method : wrapper.getMethods()) {
|
||||
if (CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && method.root != null) {
|
||||
Statement firstData = Statements.findFirstData(method.root);
|
||||
if (firstData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int index = 0;
|
||||
List<Exprent> lstExprents = firstdata.getExprents();
|
||||
List<Exprent> lstExprents = firstData.getExprents();
|
||||
|
||||
for (Exprent exprent : lstExprents) {
|
||||
|
||||
int action = 0;
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||
AssignmentExprent asexpr = (AssignmentExprent)exprent;
|
||||
if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
|
||||
FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
|
||||
if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
|
||||
StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString);
|
||||
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
|
||||
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD && assignExpr.getRight().type == Exprent.EXPRENT_VAR) {
|
||||
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
|
||||
if (fExpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
|
||||
StructField structField = wrapper.getClassStruct().getField(fExpr.getName(), fExpr.getDescriptor().descriptorString);
|
||||
if (structField != null && structField.hasModifier(CodeConstants.ACC_FINAL)) {
|
||||
action = 1;
|
||||
}
|
||||
@ -83,7 +63,7 @@ public class InitializerProcessor {
|
||||
}
|
||||
}
|
||||
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()
|
||||
lstExprents.add(0, lstExprents.remove(index));
|
||||
action = 2;
|
||||
@ -99,52 +79,50 @@ public class InitializerProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void hideEmptySuper(ClassWrapper wrapper) {
|
||||
|
||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
||||
if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
|
||||
Statement firstdata = findFirstData(meth.root);
|
||||
if (firstdata == null || firstdata.getExprents().isEmpty()) {
|
||||
for (MethodWrapper method : wrapper.getMethods()) {
|
||||
if (CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && method.root != null) {
|
||||
Statement firstData = Statements.findFirstData(method.root);
|
||||
if (firstData == null || firstData.getExprents().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Exprent exprent = firstdata.getExprents().get(0);
|
||||
Exprent exprent = firstData.getExprents().get(0);
|
||||
if (exprent.type == Exprent.EXPRENT_INVOCATION) {
|
||||
InvocationExprent invexpr = (InvocationExprent)exprent;
|
||||
if (isInvocationInitConstructor(invexpr, meth, wrapper, false) && invexpr.getLstParameters().isEmpty()) {
|
||||
firstdata.getExprents().remove(0);
|
||||
InvocationExprent invExpr = (InvocationExprent)exprent;
|
||||
if (Statements.isInvocationInitConstructor(invExpr, method, wrapper, false) && invExpr.getLstParameters().isEmpty()) {
|
||||
firstData.getExprents().remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper meth) {
|
||||
|
||||
RootStatement root = meth.root;
|
||||
private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper method) {
|
||||
RootStatement root = method.root;
|
||||
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);
|
||||
if (firstdata != null) {
|
||||
while (!firstdata.getExprents().isEmpty()) {
|
||||
Exprent exprent = firstdata.getExprents().get(0);
|
||||
while (!firstData.getExprents().isEmpty()) {
|
||||
Exprent exprent = firstData.getExprents().get(0);
|
||||
|
||||
boolean found = false;
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||
AssignmentExprent asexpr = (AssignmentExprent)exprent;
|
||||
if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
||||
FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
|
||||
if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
|
||||
cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) {
|
||||
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
|
||||
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
||||
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
|
||||
if (fExpr.isStatic() && fExpr.getClassname().equals(cl.qualifiedName) &&
|
||||
cl.hasField(fExpr.getName(), fExpr.getDescriptor().descriptorString)) {
|
||||
|
||||
if (true || isExprentIndependent(asexpr.getRight(), meth)) { // Spigot
|
||||
|
||||
String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
|
||||
// interfaces fields should always be initialized inline
|
||||
if (inlineInitializers || isExprentIndependent(assignExpr.getRight(), method)) {
|
||||
String keyField = InterpreterUtil.makeUniqueKey(fExpr.getName(), fExpr.getDescriptor().descriptorString);
|
||||
if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) {
|
||||
wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField);
|
||||
firstdata.getExprents().remove(0);
|
||||
wrapper.getStaticFieldInitializers().addWithKey(assignExpr.getRight(), keyField);
|
||||
firstData.getExprents().remove(0);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
@ -160,27 +138,26 @@ public class InitializerProcessor {
|
||||
}
|
||||
|
||||
private static void extractDynamicInitializers(ClassWrapper wrapper) {
|
||||
|
||||
StructClass cl = wrapper.getClassStruct();
|
||||
|
||||
boolean isAnonymous = DecompilerContext.getClassProcessor().getMapRootClasses().get(cl.qualifiedName).type == ClassNode.CLASS_ANONYMOUS;
|
||||
|
||||
List<List<Exprent>> lstFirst = new ArrayList<List<Exprent>>();
|
||||
List<MethodWrapper> lstMethWrappers = new ArrayList<MethodWrapper>();
|
||||
List<List<Exprent>> lstFirst = new ArrayList<>();
|
||||
List<MethodWrapper> lstMethodWrappers = new ArrayList<>();
|
||||
|
||||
for (MethodWrapper meth : wrapper.getMethods()) {
|
||||
if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) { // successfully decompiled constructor
|
||||
Statement firstdata = findFirstData(meth.root);
|
||||
if (firstdata == null || firstdata.getExprents().isEmpty()) {
|
||||
for (MethodWrapper method : wrapper.getMethods()) {
|
||||
if (CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && method.root != null) { // successfully decompiled constructor
|
||||
Statement firstData = Statements.findFirstData(method.root);
|
||||
if (firstData == null || firstData.getExprents().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
lstFirst.add(firstdata.getExprents());
|
||||
lstMethWrappers.add(meth);
|
||||
lstFirst.add(firstData.getExprents());
|
||||
lstMethodWrappers.add(method);
|
||||
|
||||
Exprent exprent = firstdata.getExprents().get(0);
|
||||
Exprent exprent = firstData.getExprents().get(0);
|
||||
if (!isAnonymous) { // FIXME: doesn't make sense
|
||||
if (exprent.type != Exprent.EXPRENT_INVOCATION ||
|
||||
!isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, false)) {
|
||||
!Statements.isInvocationInitConstructor((InvocationExprent)exprent, method, wrapper, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -192,12 +169,10 @@ public class InitializerProcessor {
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
String fieldWithDescr = null;
|
||||
Exprent value = null;
|
||||
|
||||
for (int i = 0; i < lstFirst.size(); i++) {
|
||||
|
||||
List<Exprent> lst = lstFirst.get(i);
|
||||
|
||||
if (lst.size() < (isAnonymous ? 1 : 2)) {
|
||||
@ -209,22 +184,21 @@ public class InitializerProcessor {
|
||||
boolean found = false;
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||
AssignmentExprent asexpr = (AssignmentExprent)exprent;
|
||||
if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
||||
FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
|
||||
if (!fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
|
||||
cl.hasField(fexpr.getName(), fexpr
|
||||
.getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
|
||||
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
|
||||
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
|
||||
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
|
||||
if (!fExpr.isStatic() && fExpr.getClassname().equals(cl.qualifiedName) &&
|
||||
cl.hasField(fExpr.getName(), fExpr.getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
|
||||
|
||||
if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i))) {
|
||||
String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
|
||||
if (isExprentIndependent(assignExpr.getRight(), lstMethodWrappers.get(i))) {
|
||||
String fieldKey = InterpreterUtil.makeUniqueKey(fExpr.getName(), fExpr.getDescriptor().descriptorString);
|
||||
if (fieldWithDescr == null) {
|
||||
fieldWithDescr = fieldKey;
|
||||
value = asexpr.getRight();
|
||||
value = assignExpr.getRight();
|
||||
}
|
||||
else {
|
||||
if (!fieldWithDescr.equals(fieldKey) ||
|
||||
!value.equals(asexpr.getRight())) {
|
||||
!value.equals(assignExpr.getRight())) {
|
||||
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);
|
||||
lst.add(exprent);
|
||||
|
||||
for (Exprent expr : lst) {
|
||||
switch (expr.type) {
|
||||
case Exprent.EXPRENT_VAR:
|
||||
VarVersionPaar varpaar = new VarVersionPaar((VarExprent)expr);
|
||||
if (!meth.varproc.getExternvars().contains(varpaar)) {
|
||||
String varname = meth.varproc.getVarName(varpaar);
|
||||
|
||||
if (!varname.equals("this") && !varname.endsWith(".this")) { // FIXME: remove direct comparison with strings
|
||||
VarVersionPair varPair = new VarVersionPair((VarExprent)expr);
|
||||
if (!method.varproc.getExternalVars().contains(varPair)) {
|
||||
String varName = method.varproc.getVarName(varPair);
|
||||
if (!varName.equals("this") && !varName.endsWith(".this")) { // FIXME: remove direct comparison with strings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -276,48 +248,4 @@ public class InitializerProcessor {
|
||||
|
||||
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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructLineNumberTableAttribute;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
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
|
||||
private HashMap<Integer, Integer> mapping = new HashMap<Integer, Integer>();
|
||||
|
||||
public BytecodeMappingTracer() {}
|
||||
public BytecodeMappingTracer() { }
|
||||
|
||||
public BytecodeMappingTracer(int initial_source_line) {
|
||||
current_sourceline = initial_source_line;
|
||||
currentSourceLine = initial_source_line;
|
||||
}
|
||||
|
||||
public void incrementCurrentSourceLine() {
|
||||
current_sourceline++;
|
||||
currentSourceLine++;
|
||||
}
|
||||
|
||||
public void incrementCurrentSourceLine(int number_lines) {
|
||||
current_sourceline += number_lines;
|
||||
}
|
||||
|
||||
public void shiftSourceLines(int shift) {
|
||||
for(Entry<Integer, Integer> entry : mapping.entrySet()) {
|
||||
entry.setValue(entry.getValue() + shift);
|
||||
}
|
||||
currentSourceLine += number_lines;
|
||||
}
|
||||
|
||||
public void addMapping(int bytecode_offset) {
|
||||
if(!mapping.containsKey(bytecode_offset)) {
|
||||
mapping.put(bytecode_offset, current_sourceline);
|
||||
}
|
||||
mapping.putIfAbsent(bytecode_offset, currentSourceLine);
|
||||
}
|
||||
|
||||
public void addMapping(Set<Integer> bytecode_offsets) {
|
||||
if(bytecode_offsets != null) {
|
||||
for(Integer bytecode_offset : bytecode_offsets) {
|
||||
if (bytecode_offsets != null) {
|
||||
for (Integer bytecode_offset : bytecode_offsets) {
|
||||
addMapping(bytecode_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addTracer(BytecodeMappingTracer tracer) {
|
||||
if(tracer != null) {
|
||||
for(Entry<Integer, Integer> entry : tracer.mapping.entrySet()) {
|
||||
if(!mapping.containsKey(entry.getKey())) {
|
||||
mapping.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (tracer != null) {
|
||||
for (Entry<Integer, Integer> entry : tracer.mapping.entrySet()) {
|
||||
mapping.putIfAbsent(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HashMap<Integer, Integer> getMapping() {
|
||||
public Map<Integer, Integer> getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public int getCurrentSourceLine() {
|
||||
return current_sourceline;
|
||||
return currentSourceLine;
|
||||
}
|
||||
|
||||
public void setCurrentSourceLine(int current_sourceline) {
|
||||
this.current_sourceline = current_sourceline;
|
||||
public void setCurrentSourceLine(int currentSourceLine) {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
public class BytecodeSourceMapper {
|
||||
|
||||
private int offset_total;
|
||||
|
||||
// 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);
|
||||
if(class_mapping == null) {
|
||||
mapping.put(classname, class_mapping = new HashMap<String, HashMap<Integer, Integer>>());
|
||||
}
|
||||
|
||||
HashMap<Integer, Integer> method_mapping = class_mapping.get(methodname);
|
||||
if(method_mapping == null) {
|
||||
class_mapping.put(methodname, method_mapping = new HashMap<Integer, Integer>());
|
||||
}
|
||||
public void addMapping(String className, String methodName, int bytecodeOffset, int sourceLine) {
|
||||
Map<String, Map<Integer, Integer>> class_mapping = mapping.computeIfAbsent(className, k -> new LinkedHashMap<>()); // need to preserve order
|
||||
Map<Integer, Integer> method_mapping = class_mapping.computeIfAbsent(methodName, k -> new HashMap<>());
|
||||
|
||||
// don't overwrite
|
||||
if(!method_mapping.containsKey(bytecode_offset)) {
|
||||
method_mapping.put(bytecode_offset, source_line);
|
||||
}
|
||||
method_mapping.putIfAbsent(bytecodeOffset, sourceLine);
|
||||
}
|
||||
|
||||
public void addTracer(String classname, String methodname, BytecodeMappingTracer tracer) {
|
||||
for(Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
|
||||
addMapping(classname, methodname, entry.getKey(), entry.getValue());
|
||||
public void addTracer(String className, String methodName, BytecodeMappingTracer tracer) {
|
||||
for (Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
|
||||
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();
|
||||
|
||||
for(Entry<String, HashMap<String, HashMap<Integer, Integer>>> class_entry : mapping.entrySet()) {
|
||||
HashMap<String, HashMap<Integer, Integer>> class_mapping = class_entry.getValue();
|
||||
buffer.append("class " + class_entry.getKey() + "{" + lineSeparator);
|
||||
for (Entry<String, Map<String, Map<Integer, Integer>>> class_entry : mapping.entrySet()) {
|
||||
Map<String, Map<Integer, Integer>> class_mapping = class_entry.getValue();
|
||||
buffer.append("class '" + class_entry.getKey() + "' {" + lineSeparator);
|
||||
|
||||
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()) {
|
||||
HashMap<Integer, Integer> method_mapping = method_entry.getValue();
|
||||
|
||||
if(!is_first_method) {
|
||||
if (!is_first_method) {
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
buffer.appendIndent(1).append("method " + method_entry.getKey() + "{" + lineSeparator);
|
||||
|
||||
for(Entry<Integer, Integer> line : method_mapping.entrySet()) {
|
||||
buffer.appendIndent(2).append(line.getKey().toString()).appendIndent(2).append((line.getValue() + offset_total) + lineSeparator);
|
||||
buffer.appendIndent(1).append("method '" + method_entry.getKey() + "' {" + 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();
|
||||
|
||||
is_first_method = false;
|
||||
}
|
||||
buffer.append("}").appendLineSeparator();
|
||||
|
||||
buffer.append("}").appendLineSeparator().appendLineSeparator();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalOffset() {
|
||||
return offset_total;
|
||||
}
|
||||
// lines mapping
|
||||
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) {
|
||||
this.offset_total = offset_total;
|
||||
if (!unmappedLines.isEmpty()) {
|
||||
buffer.append("Not mapped:").appendLineSeparator();
|
||||
for (Integer line : unmappedLines) {
|
||||
if (!linesMapping.containsKey(line)) {
|
||||
buffer.append(line).appendLineSeparator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addTotalOffset(int 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-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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.collectors;
|
||||
|
||||
public class CounterContainer {
|
||||
|
||||
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;
|
||||
|
||||
private int[] values = new int[]{1, 1, 1};
|
||||
private final int[] values = new int[]{1, 1, 1};
|
||||
|
||||
public void setCounter(int counter, int value) {
|
||||
values[counter] = value;
|
||||
@ -34,4 +19,4 @@ public class CounterContainer {
|
||||
public int getCounterAndIncrement(int counter) {
|
||||
return values[counter]++;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,155 +1,186 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
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.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.StructField;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ImportCollector {
|
||||
|
||||
private static final String JAVA_LANG_PACKAGE = "java.lang";
|
||||
|
||||
private Map<String, String> mapSimpleNames = new HashMap<String, String>();
|
||||
private Set<String> setNotImportedNames = new HashSet<String>();
|
||||
private String currentPackageSlash = "";
|
||||
private String currentPackagePoint = "";
|
||||
private final Map<String, String> mapSimpleNames = new HashMap<>();
|
||||
private final Set<String> setNotImportedNames = new HashSet<>();
|
||||
// set of field names in this class and all its predecessors.
|
||||
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) {
|
||||
|
||||
String clname = root.classStruct.qualifiedName;
|
||||
int index = clname.lastIndexOf("/");
|
||||
String clName = root.classStruct.qualifiedName;
|
||||
int index = clName.lastIndexOf('/');
|
||||
if (index >= 0) {
|
||||
currentPackageSlash = clname.substring(0, index);
|
||||
currentPackagePoint = currentPackageSlash.replace('/', '.');
|
||||
currentPackageSlash += "/";
|
||||
String packageName = clName.substring(0, index);
|
||||
currentPackageSlash = packageName + '/';
|
||||
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();
|
||||
ClassNode node = clproc.getMapRootClasses().get(fullname.replace('.', '/'));
|
||||
|
||||
String retname = null;
|
||||
public String getShortName(String fullName, boolean imported) {
|
||||
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(fullName.replace('.', '/')); //todo[r.sh] anonymous classes?
|
||||
|
||||
String result = null;
|
||||
if (node != null && node.classStruct.isOwn()) {
|
||||
|
||||
retname = node.simpleName;
|
||||
result = node.simpleName;
|
||||
|
||||
while (node.parent != null && node.type == ClassNode.CLASS_MEMBER) {
|
||||
retname = node.parent.simpleName + "." + retname;
|
||||
//noinspection StringConcatenationInLoop
|
||||
result = node.parent.simpleName + '.' + result;
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
if (node.type == ClassNode.CLASS_ROOT) {
|
||||
fullname = node.classStruct.qualifiedName;
|
||||
fullname = fullname.replace('/', '.');
|
||||
fullName = node.classStruct.qualifiedName;
|
||||
fullName = fullName.replace('/', '.');
|
||||
}
|
||||
else {
|
||||
return retname;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fullname = fullname.replace('$', '.');
|
||||
fullName = fullName.replace('$', '.');
|
||||
}
|
||||
|
||||
String nshort = fullname;
|
||||
String npackage = "";
|
||||
String shortName = fullName;
|
||||
String packageName = "";
|
||||
|
||||
int lastpoint = fullname.lastIndexOf(".");
|
||||
|
||||
if (lastpoint >= 0) {
|
||||
nshort = fullname.substring(lastpoint + 1);
|
||||
npackage = fullname.substring(0, lastpoint);
|
||||
int lastDot = fullName.lastIndexOf('.');
|
||||
if (lastDot >= 0) {
|
||||
shortName = fullName.substring(lastDot + 1);
|
||||
packageName = fullName.substring(0, lastDot);
|
||||
}
|
||||
|
||||
StructContext context = DecompilerContext.getStructContext();
|
||||
|
||||
boolean existsDefaultClass = (context.getClass(currentPackageSlash + nshort) != null
|
||||
&& !npackage.equals(currentPackagePoint)) // current package
|
||||
|| (context.getClass(nshort) != null); // default package
|
||||
// check for another class which could 'shadow' this one. Three cases:
|
||||
// 1) class with the same short name in the current 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 ||
|
||||
(mapSimpleNames.containsKey(nshort) && !npackage.equals(mapSimpleNames.get(nshort)))) {
|
||||
return fullname;
|
||||
(mapSimpleNames.containsKey(shortName) && !packageName.equals(mapSimpleNames.get(shortName)))) {
|
||||
// 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)) {
|
||||
mapSimpleNames.put(nshort, npackage);
|
||||
|
||||
else if (!mapSimpleNames.containsKey(shortName)) {
|
||||
mapSimpleNames.put(shortName, packageName);
|
||||
if (!imported) {
|
||||
setNotImportedNames.add(nshort);
|
||||
setNotImportedNames.add(shortName);
|
||||
}
|
||||
}
|
||||
|
||||
return retname == null ? nshort : retname;
|
||||
return result == null ? shortName : result;
|
||||
}
|
||||
|
||||
public int writeImports(TextBuffer buffer) {
|
||||
|
||||
int importlines_written = 0;
|
||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||
|
||||
public void writeImports(TextBuffer buffer, boolean addSeparator) {
|
||||
List<String> imports = packImports();
|
||||
|
||||
for (String s : imports) {
|
||||
buffer.append("import ");
|
||||
buffer.append(s);
|
||||
buffer.append(";");
|
||||
buffer.append(new_line_separator);
|
||||
|
||||
importlines_written++;
|
||||
for (String line : imports) {
|
||||
buffer.append("import ").append(line).append(';').appendLineSeparator();
|
||||
}
|
||||
if (addSeparator && !imports.isEmpty()) {
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
|
||||
return importlines_written;
|
||||
}
|
||||
|
||||
private List<String> packImports() {
|
||||
List<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(mapSimpleNames.entrySet());
|
||||
|
||||
Collections.sort(lst, new Comparator<Entry<String, String>>() {
|
||||
public int compare(Entry<String, String> par0, Entry<String, String> par1) {
|
||||
int res = par0.getValue().compareTo(par1.getValue());
|
||||
if (res == 0) {
|
||||
res = par0.getKey().compareTo(par1.getKey());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
return mapSimpleNames.entrySet().stream()
|
||||
.filter(ent ->
|
||||
// exclude the current class or one of the nested ones
|
||||
// empty, java.lang and the current packages
|
||||
!setNotImportedNames.contains(ent.getKey()) &&
|
||||
!ent.getValue().isEmpty() &&
|
||||
!JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
|
||||
!ent.getValue().equals(currentPackagePoint)
|
||||
)
|
||||
.sorted(Map.Entry.<String, String>comparingByValue().thenComparing(Map.Entry.comparingByKey()))
|
||||
.map(ent -> ent.getValue() + "." + ent.getKey())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
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.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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) {
|
||||
usedNames.addAll(setNames);
|
||||
@ -33,20 +24,140 @@ public class VarNamesCollector {
|
||||
usedNames.add(value);
|
||||
}
|
||||
|
||||
public String getFreeName(int index) {
|
||||
return getFreeName("var" + index);
|
||||
}
|
||||
|
||||
public String getFreeName(String proposition) {
|
||||
|
||||
while (usedNames.contains(proposition)) {
|
||||
proposition += "x";
|
||||
public static String removePrefix(String str, String prefix)
|
||||
{
|
||||
if (str.toLowerCase().startsWith(prefix))
|
||||
{
|
||||
return str.substring(prefix.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
return str;
|
||||
}
|
||||
usedNames.add(proposition);
|
||||
return proposition;
|
||||
}
|
||||
|
||||
public HashSet<String> getUsedNames() {
|
||||
return usedNames;
|
||||
public String getTypeLabel(VarType type, int index) {
|
||||
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-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.
|
||||
*/
|
||||
// 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.decompiler;
|
||||
|
||||
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 java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class BaseDecompiler {
|
||||
|
||||
private final Fernflower fernflower;
|
||||
private final Fernflower engine;
|
||||
|
||||
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 {
|
||||
fernflower.getStructContext().addSpace(file, isOwn);
|
||||
public void addSource(File source) {
|
||||
engine.addSource(source);
|
||||
}
|
||||
|
||||
public void addLibrary(File library) {
|
||||
engine.addLibrary(library);
|
||||
}
|
||||
|
||||
public void decompileContext() {
|
||||
try {
|
||||
fernflower.decompileContext();
|
||||
engine.decompileContext();
|
||||
}
|
||||
finally {
|
||||
fernflower.clearContext();
|
||||
engine.clearContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.decompiler;
|
||||
|
||||
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 java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
@ -31,7 +18,6 @@ import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public static void main(String[] args) {
|
||||
if (args.length < 2) {
|
||||
@ -41,21 +27,20 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> mapOptions = new HashMap<String, Object>();
|
||||
List<String> lstSources = new ArrayList<String>();
|
||||
List<String> lstLibraries = new ArrayList<String>();
|
||||
Map<String, Object> mapOptions = new HashMap<>();
|
||||
List<File> sources = new ArrayList<>();
|
||||
List<File> libraries = new ArrayList<>();
|
||||
|
||||
boolean isOption = true;
|
||||
for (int i = 0; i < args.length - 1; ++i) { // last parameter - destination
|
||||
String arg = args[i];
|
||||
|
||||
if (isOption && arg.startsWith("-") &&
|
||||
arg.length() > 5 && arg.charAt(4) == '=') {
|
||||
String value = arg.substring(5).toUpperCase(Locale.US);
|
||||
if ("TRUE".equals(value)) {
|
||||
if (isOption && arg.length() > 5 && arg.charAt(0) == '-' && arg.charAt(4) == '=') {
|
||||
String value = arg.substring(5);
|
||||
if ("true".equalsIgnoreCase(value)) {
|
||||
value = "1";
|
||||
}
|
||||
else if ("FALSE".equals(value)) {
|
||||
else if ("false".equalsIgnoreCase(value)) {
|
||||
value = "0";
|
||||
}
|
||||
|
||||
@ -65,15 +50,15 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
isOption = false;
|
||||
|
||||
if (arg.startsWith("-e=")) {
|
||||
lstLibraries.add(arg.substring(3));
|
||||
addPath(libraries, arg.substring(3));
|
||||
}
|
||||
else {
|
||||
lstSources.add(arg);
|
||||
addPath(sources, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lstSources.isEmpty()) {
|
||||
if (sources.isEmpty()) {
|
||||
System.out.println("error: no sources given");
|
||||
return;
|
||||
}
|
||||
@ -87,45 +72,55 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
PrintStreamLogger logger = new PrintStreamLogger(System.out);
|
||||
ConsoleDecompiler decompiler = new ConsoleDecompiler(destination, mapOptions, logger);
|
||||
|
||||
for (String source : lstSources) {
|
||||
decompiler.addSpace(new File(source), true);
|
||||
for (File library : libraries) {
|
||||
decompiler.addLibrary(library);
|
||||
}
|
||||
for (String library : lstLibraries) {
|
||||
decompiler.addSpace(new File(library), false);
|
||||
for (File source : sources) {
|
||||
decompiler.addSource(source);
|
||||
}
|
||||
|
||||
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
|
||||
// *******************************************************************
|
||||
|
||||
private final File root;
|
||||
private final Fernflower fernflower;
|
||||
private Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<String, ZipOutputStream>();
|
||||
private Map<String, Set<String>> mapArchiveEntries = new HashMap<String, Set<String>>();
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public ConsoleDecompiler(File destination, Map<String, Object> options) {
|
||||
this(destination, options, new PrintStreamLogger(System.out));
|
||||
}
|
||||
private final Fernflower engine;
|
||||
private final Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<>();
|
||||
private final Map<String, Set<String>> mapArchiveEntries = new HashMap<>();
|
||||
|
||||
protected ConsoleDecompiler(File destination, Map<String, Object> options, IFernflowerLogger logger) {
|
||||
root = destination;
|
||||
fernflower = new Fernflower(this, this, options, logger);
|
||||
engine = new Fernflower(this, this, options, logger);
|
||||
}
|
||||
|
||||
public void addSpace(File file, boolean isOwn) {
|
||||
fernflower.getStructContext().addSpace(file, isOwn);
|
||||
public void addSource(File source) {
|
||||
engine.addSource(source);
|
||||
}
|
||||
|
||||
public void addLibrary(File library) {
|
||||
engine.addLibrary(library);
|
||||
}
|
||||
|
||||
public void decompileContext() {
|
||||
try {
|
||||
fernflower.decompileContext();
|
||||
engine.decompileContext();
|
||||
}
|
||||
finally {
|
||||
fernflower.clearContext();
|
||||
engine.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,17 +135,11 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
return InterpreterUtil.getBytes(file);
|
||||
}
|
||||
else {
|
||||
ZipFile archive = new ZipFile(file);
|
||||
try {
|
||||
try (ZipFile archive = new ZipFile(file)) {
|
||||
ZipEntry entry = archive.getEntry(internalPath);
|
||||
if (entry == null) {
|
||||
throw new IOException("Entry not found: " + internalPath);
|
||||
}
|
||||
if (entry == null) throw new IOException("Entry not found: " + internalPath);
|
||||
return InterpreterUtil.getBytes(archive, entry);
|
||||
}
|
||||
finally {
|
||||
archive.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,16 +170,10 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
}
|
||||
|
||||
@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);
|
||||
try {
|
||||
Writer out = new OutputStreamWriter(new FileOutputStream(file), "UTF8");
|
||||
try {
|
||||
out.write(content);
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
try (Writer out = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
|
||||
out.write(content);
|
||||
}
|
||||
catch (IOException 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);
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
ZipOutputStream zipStream = manifest != null ? new JarOutputStream(fileStream, manifest) : new ZipOutputStream(fileStream);
|
||||
mapArchiveStreams.put(file.getPath(), zipStream);
|
||||
}
|
||||
@ -228,21 +210,15 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ZipFile srcArchive = new ZipFile(new File(source));
|
||||
try {
|
||||
ZipEntry entry = srcArchive.getEntry(entryName);
|
||||
if (entry != null) {
|
||||
InputStream in = srcArchive.getInputStream(entry);
|
||||
try (ZipFile srcArchive = new ZipFile(new File(source))) {
|
||||
ZipEntry entry = srcArchive.getEntry(entryName);
|
||||
if (entry != null) {
|
||||
try (InputStream in = srcArchive.getInputStream(entry)) {
|
||||
ZipOutputStream out = mapArchiveStreams.get(file);
|
||||
out.putNextEntry(new ZipEntry(entryName));
|
||||
InterpreterUtil.copyStream(in, out);
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
srcArchive.close();
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
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);
|
||||
out.putNextEntry(new ZipEntry(entryName));
|
||||
if (content != null) {
|
||||
out.write(content.getBytes("UTF-8"));
|
||||
out.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
@ -272,10 +248,7 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
}
|
||||
|
||||
private boolean checkEntry(String entryName, String file) {
|
||||
Set<String> set = mapArchiveEntries.get(file);
|
||||
if (set == null) {
|
||||
mapArchiveEntries.put(file, set = new HashSet<String>());
|
||||
}
|
||||
Set<String> set = mapArchiveEntries.computeIfAbsent(file, k -> new HashSet<>());
|
||||
|
||||
boolean added = set.add(entryName);
|
||||
if (!added) {
|
||||
@ -296,4 +269,4 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
|
||||
DecompilerContext.getLogger().writeMessage("Cannot close " + file, IFernflowerLogger.Severity.WARN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.decompiler;
|
||||
|
||||
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;
|
||||
|
||||
@ -33,62 +19,79 @@ public class PrintStreamLogger extends IFernflowerLogger {
|
||||
@Override
|
||||
public void writeMessage(String message, Severity severity) {
|
||||
if (accepts(severity)) {
|
||||
stream.println(severity.prefix + InterpreterUtil.getIndentString(indent) + message);
|
||||
stream.println(severity.prefix + TextUtil.getIndentString(indent) + message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessage(String message, Throwable t) {
|
||||
writeMessage(message, Severity.ERROR);
|
||||
if (accepts(Severity.ERROR)) {
|
||||
public void writeMessage(String message, Severity severity, Throwable t) {
|
||||
if (accepts(severity)) {
|
||||
writeMessage(message, severity);
|
||||
t.printStackTrace(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startReadingClass(String className) {
|
||||
writeMessage("Decompiling class " + className, Severity.INFO);
|
||||
++indent;
|
||||
if (accepts(Severity.INFO)) {
|
||||
writeMessage("Decompiling class " + className, Severity.INFO);
|
||||
++indent;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endReadingClass() {
|
||||
--indent;
|
||||
writeMessage("... done", Severity.INFO);
|
||||
if (accepts(Severity.INFO)) {
|
||||
--indent;
|
||||
writeMessage("... done", Severity.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startClass(String className) {
|
||||
writeMessage("Processing class " + className, Severity.TRACE);
|
||||
++indent;
|
||||
if (accepts(Severity.INFO)) {
|
||||
writeMessage("Processing class " + className, Severity.TRACE);
|
||||
++indent;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endClass() {
|
||||
--indent;
|
||||
writeMessage("... proceeded", Severity.TRACE);
|
||||
if (accepts(Severity.INFO)) {
|
||||
--indent;
|
||||
writeMessage("... proceeded", Severity.TRACE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startMethod(String methodName) {
|
||||
writeMessage("Processing method " + methodName, Severity.TRACE);
|
||||
++indent;
|
||||
if (accepts(Severity.INFO)) {
|
||||
writeMessage("Processing method " + methodName, Severity.TRACE);
|
||||
++indent;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endMethod() {
|
||||
--indent;
|
||||
writeMessage("... proceeded", Severity.TRACE);
|
||||
if (accepts(Severity.INFO)) {
|
||||
--indent;
|
||||
writeMessage("... proceeded", Severity.TRACE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startWriteClass(String className) {
|
||||
writeMessage("Writing class " + className, Severity.TRACE);
|
||||
++indent;
|
||||
if (accepts(Severity.INFO)) {
|
||||
writeMessage("Writing class " + className, Severity.TRACE);
|
||||
++indent;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endWriteClass() {
|
||||
--indent;
|
||||
writeMessage("... written", Severity.TRACE);
|
||||
if (accepts(Severity.INFO)) {
|
||||
--indent;
|
||||
writeMessage("... written", Severity.TRACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.extern;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.extern;
|
||||
|
||||
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, 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) { }
|
||||
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.extern;
|
||||
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
@ -31,6 +17,7 @@ public interface IFernflowerPreferences {
|
||||
String HIDE_DEFAULT_CONSTRUCTOR = "hdc";
|
||||
String DECOMPILE_GENERIC_SIGNATURES = "dgs";
|
||||
String NO_EXCEPTIONS_RETURN = "ner";
|
||||
String ENSURE_SYNCHRONIZED_MONITOR = "esm";
|
||||
String DECOMPILE_ENUM = "den";
|
||||
String REMOVE_GET_CLASS_NEW = "rgn";
|
||||
String LITERALS_AS_IS = "lit";
|
||||
@ -39,13 +26,14 @@ public interface IFernflowerPreferences {
|
||||
String SYNTHETIC_NOT_SET = "nns";
|
||||
String UNDEFINED_PARAM_TYPE_OBJECT = "uto";
|
||||
String USE_DEBUG_VAR_NAMES = "udv";
|
||||
String USE_METHOD_PARAMETERS = "ump";
|
||||
String REMOVE_EMPTY_RANGES = "rer";
|
||||
String FINALLY_DEINLINE = "fdi";
|
||||
String IDEA_NOT_NULL_ANNOTATION = "inn";
|
||||
String LAMBDA_TO_ANONYMOUS_CLASS = "lac";
|
||||
|
||||
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 MAX_PROCESSING_METHOD = "mpm";
|
||||
@ -53,44 +41,55 @@ public interface IFernflowerPreferences {
|
||||
String USER_RENAMER_CLASS = "urc";
|
||||
String NEW_LINE_SEPARATOR = "nls";
|
||||
String INDENT_STRING = "ind";
|
||||
|
||||
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_LIN = "\n";
|
||||
String LINE_SEPARATOR_UNX = "\n";
|
||||
|
||||
Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>() {{
|
||||
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");
|
||||
Map<String, Object> DEFAULTS = getDefaults();
|
||||
|
||||
put(BYTECODE_SOURCE_MAPPING, "0");
|
||||
put(USE_DEBUG_LINE_NUMBERS, "0");
|
||||
static Map<String, Object> getDefaults() {
|
||||
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());
|
||||
put(MAX_PROCESSING_METHOD, "0");
|
||||
put(RENAME_ENTITIES, "0");
|
||||
put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1"));
|
||||
put(INDENT_STRING, " ");
|
||||
}});
|
||||
}
|
||||
defaults.put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name());
|
||||
defaults.put(MAX_PROCESSING_METHOD, "0");
|
||||
defaults.put(RENAME_ENTITIES, "0");
|
||||
defaults.put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1"));
|
||||
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-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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.extern;
|
||||
|
||||
|
||||
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 getNextClassname(String fullname, String shortname);
|
||||
|
||||
String getNextFieldname(String classname, String field, String descriptor);
|
||||
|
||||
String getNextMethodname(String classname, String method, String descriptor);
|
||||
String getNextMethodName(String className, String method, String descriptor);
|
||||
}
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.extern;
|
||||
|
||||
import java.util.jar.Manifest;
|
||||
@ -22,7 +8,7 @@ public interface IResultSaver {
|
||||
|
||||
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);
|
||||
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.rels;
|
||||
|
||||
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.IFernflowerPreferences;
|
||||
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.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.StructField;
|
||||
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.gen.MethodDescriptor;
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ClassWrapper {
|
||||
|
||||
private StructClass classStruct;
|
||||
private Set<String> hiddenMembers = new HashSet<String>();
|
||||
private VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<Exprent, String>();
|
||||
private VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<Exprent, String>();
|
||||
private VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<MethodWrapper, String>();
|
||||
|
||||
private final StructClass classStruct;
|
||||
private final Set<String> hiddenMembers = new HashSet<>();
|
||||
private final VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<>();
|
||||
private final VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<>();
|
||||
private final VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<>();
|
||||
|
||||
public ClassWrapper(StructClass classStruct) {
|
||||
this.classStruct = classStruct;
|
||||
}
|
||||
|
||||
public void init() throws IOException {
|
||||
|
||||
public void init() {
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
|
||||
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_WRAPPER, this);
|
||||
DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
|
||||
|
||||
// collect field names
|
||||
HashSet<String> setFieldNames = new HashSet<String>();
|
||||
for (StructField fd : classStruct.getFields()) {
|
||||
setFieldNames.add(fd.getName());
|
||||
}
|
||||
|
||||
int maxsec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
|
||||
int maxSec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
|
||||
boolean testMode = DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE);
|
||||
|
||||
for (StructMethod mt : classStruct.getMethods()) {
|
||||
|
||||
DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
|
||||
|
||||
VarNamesCollector vc = new VarNamesCollector();
|
||||
DecompilerContext.setVarNamesCollector(vc);
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
||||
VarProcessor varProc = new VarProcessor(mt, md);
|
||||
DecompilerContext.startMethod(varProc);
|
||||
|
||||
CounterContainer counter = new CounterContainer();
|
||||
DecompilerContext.setCounterContainer(counter);
|
||||
|
||||
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);
|
||||
VarNamesCollector vc = varProc.getVarNamesCollector();
|
||||
CounterContainer counter = DecompilerContext.getCounterContainer();
|
||||
|
||||
RootStatement root = null;
|
||||
|
||||
@ -87,86 +58,113 @@ public class ClassWrapper {
|
||||
|
||||
try {
|
||||
if (mt.containsCode()) {
|
||||
|
||||
if (maxsec == 0) { // blocking wait
|
||||
root = MethodProcessorThread.codeToJava(mt, varproc);
|
||||
if (maxSec == 0 || testMode) {
|
||||
root = MethodProcessorRunnable.codeToJava(classStruct, mt, md, varProc);
|
||||
}
|
||||
else {
|
||||
MethodProcessorThread mtproc = new MethodProcessorThread(mt, varproc, DecompilerContext.getCurrentContext());
|
||||
Thread mtthread = new Thread(mtproc);
|
||||
long stopAt = System.currentTimeMillis() + maxsec * 1000;
|
||||
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(classStruct, mt, md, varProc, DecompilerContext.getCurrentContext());
|
||||
|
||||
mtthread.start();
|
||||
Thread mtThread = new Thread(mtProc, "Java decompiler");
|
||||
long stopAt = System.currentTimeMillis() + maxSec * 1000L;
|
||||
|
||||
while (mtthread.isAlive()) {
|
||||
mtThread.start();
|
||||
|
||||
synchronized (mtproc.lock) {
|
||||
mtproc.lock.wait(100);
|
||||
while (!mtProc.isFinished()) {
|
||||
try {
|
||||
synchronized (mtProc.lock) {
|
||||
mtProc.lock.wait(200);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
killThread(mtThread);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() >= stopAt) {
|
||||
String message = "Processing time limit exceeded for method " + mt.getName() + ", execution interrupted.";
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR);
|
||||
killThread(mtthread);
|
||||
killThread(mtThread);
|
||||
isError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isError) {
|
||||
root = mtproc.getResult();
|
||||
root = mtProc.getResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
||||
boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
||||
|
||||
int paramcount = 0;
|
||||
if (thisvar) {
|
||||
varproc.getThisvars().put(new VarVersionPaar(0, 0), classStruct.qualifiedName);
|
||||
paramcount = 1;
|
||||
int paramCount = 0;
|
||||
if (thisVar) {
|
||||
varProc.getThisVars().put(new VarVersionPair(0, 0), classStruct.qualifiedName);
|
||||
paramCount = 1;
|
||||
}
|
||||
paramcount += md.params.length;
|
||||
paramCount += md.params.length;
|
||||
|
||||
int varindex = 0;
|
||||
for (int i = 0; i < paramcount; i++) {
|
||||
varproc.setVarName(new VarVersionPaar(varindex, 0, classStruct.qualifiedName, false), vc.getFreeName(varindex));
|
||||
int varIndex = 0;
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
varProc.setVarName(new VarVersionPair(varIndex, 0), "tbd");//, vc.getFreeName(varIndex));
|
||||
|
||||
if (thisvar) {
|
||||
if (thisVar) {
|
||||
if (i == 0) {
|
||||
varindex++;
|
||||
varIndex++;
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.", ex);
|
||||
catch (Throwable t) {
|
||||
String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.";
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, t);
|
||||
isError = true;
|
||||
}
|
||||
|
||||
MethodWrapper meth = new MethodWrapper(root, varproc, mt, counter);
|
||||
meth.decompiledWithErrors = isError;
|
||||
MethodWrapper methodWrapper = new MethodWrapper(root, varProc, mt, counter);
|
||||
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
|
||||
varproc.refreshVarNames(new VarNamesCollector(setFieldNames));
|
||||
if (!isError) {
|
||||
// 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 (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
||||
StructLocalVariableTableAttribute attr = (StructLocalVariableTableAttribute)mt.getAttributes().getWithKey(
|
||||
StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE);
|
||||
// if debug information present and should be used
|
||||
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
||||
StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr();
|
||||
if (attr != null) {
|
||||
// only param names here
|
||||
varProc.setDebugVarNames(attr.getMapParamNames());
|
||||
|
||||
if (attr != null) {
|
||||
varproc.setDebugVarNames(attr.getMapVarNames());
|
||||
// the rest is here
|
||||
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() {
|
||||
return dynamicFieldInitializers;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return classStruct.qualifiedName;
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.rels;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
@ -35,36 +21,28 @@ import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class LambdaProcessor {
|
||||
|
||||
@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_ALT_METHOD = "altMetafactory";
|
||||
|
||||
public void processClass(ClassNode node) throws IOException {
|
||||
|
||||
for (ClassNode child : node.nested) {
|
||||
processClass(child);
|
||||
}
|
||||
|
||||
hasLambda(node);
|
||||
}
|
||||
|
||||
public boolean hasLambda(ClassNode node) throws IOException {
|
||||
|
||||
ClassesProcessor clprocessor = DecompilerContext.getClassProcessor();
|
||||
ClassesProcessor clProcessor = DecompilerContext.getClassProcessor();
|
||||
StructClass cl = node.classStruct;
|
||||
|
||||
if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lamda beginning with Java 8
|
||||
return false;
|
||||
if (!cl.isVersion8()) { // lambda beginning with Java 8
|
||||
return;
|
||||
}
|
||||
|
||||
StructBootstrapMethodsAttribute bootstrap =
|
||||
(StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
||||
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
||||
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
|
||||
for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
|
||||
@ -73,19 +51,19 @@ public class LambdaProcessor {
|
||||
// FIXME: extend for Eclipse etc. at some point
|
||||
if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
|
||||
(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()) {
|
||||
return false; // no lambda bootstrap constant found
|
||||
if (lambdaMethods.isEmpty()) {
|
||||
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.
|
||||
for (StructMethod mt : cl.getMethods()) {
|
||||
mt.expandData();
|
||||
mt.expandData(cl);
|
||||
|
||||
InstructionSequence seq = mt.getInstructionSequence();
|
||||
if (seq != null && seq.length() > 0) {
|
||||
@ -95,9 +73,9 @@ public class LambdaProcessor {
|
||||
Instruction instr = seq.getInstr(i);
|
||||
|
||||
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);
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
|
||||
@ -117,9 +95,9 @@ public class LambdaProcessor {
|
||||
node.nested.add(node_lambda);
|
||||
node_lambda.parent = node;
|
||||
|
||||
clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
|
||||
if (!node_lambda.lambda_information.is_method_reference) {
|
||||
mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName);
|
||||
clProcessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
|
||||
if (!node_lambda.lambdaInformation.is_method_reference) {
|
||||
mapMethodsLambda.put(node_lambda.lambdaInformation.content_method_key, node_lambda.simpleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,7 +112,7 @@ public class LambdaProcessor {
|
||||
if (nd.type == ClassNode.CLASS_LAMBDA) {
|
||||
String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
|
||||
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);
|
||||
nd.parent = parent_class;
|
||||
@ -143,7 +121,5 @@ public class LambdaProcessor {
|
||||
}
|
||||
|
||||
// FIXME: mixed hierarchy?
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,7 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
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.cfg.ControlFlowGraph;
|
||||
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.struct.StructClass;
|
||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class MethodProcessorThread implements Runnable {
|
||||
|
||||
public class MethodProcessorRunnable implements Runnable {
|
||||
public final Object lock = new Object();
|
||||
|
||||
private final StructClass klass;
|
||||
private final StructMethod method;
|
||||
private final VarProcessor varproc;
|
||||
private final MethodDescriptor methodDescriptor;
|
||||
private final VarProcessor varProc;
|
||||
private final DecompilerContext parentContext;
|
||||
|
||||
private volatile RootStatement root;
|
||||
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.varproc = varproc;
|
||||
this.methodDescriptor = methodDescriptor;
|
||||
this.varProc = varProc;
|
||||
this.parentContext = parentContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
DecompilerContext.setCurrentContext(parentContext);
|
||||
|
||||
error = null;
|
||||
root = null;
|
||||
|
||||
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) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
catch (ThreadDeath ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
error = ex;
|
||||
finished = true;
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
|
||||
|
||||
mt.expandData();
|
||||
mt.expandData(cl);
|
||||
InstructionSequence seq = mt.getInstructionSequence();
|
||||
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);
|
||||
graph.inlineJsr(mt);
|
||||
|
||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern4.dot"), true);
|
||||
graph.inlineJsr(cl, mt);
|
||||
|
||||
// TODO: move to the start, before jsr inlining
|
||||
DeadCodeHelper.connectDummyExitBlock(graph);
|
||||
|
||||
DeadCodeHelper.removeGotos(graph);
|
||||
|
||||
ExceptionDeobfuscator.removeCircularRanges(graph);
|
||||
//DeadCodeHelper.removeCircularRanges(graph);
|
||||
|
||||
|
||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
||||
|
||||
ExceptionDeobfuscator.restorePopRanges(graph);
|
||||
|
||||
@ -110,15 +89,16 @@ public class MethodProcessorThread implements Runnable {
|
||||
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)) {
|
||||
// special case: single return instruction outside of a protected range
|
||||
DeadCodeHelper.incorporateValueReturns(graph);
|
||||
}
|
||||
|
||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
|
||||
|
||||
// ExceptionDeobfuscator.restorePopRanges(graph);
|
||||
ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);
|
||||
|
||||
@ -126,22 +106,18 @@ public class MethodProcessorThread implements Runnable {
|
||||
|
||||
DecompilerContext.getCounterContainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());
|
||||
|
||||
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
||||
//System.out.println(graph.toString());
|
||||
|
||||
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
|
||||
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);
|
||||
|
||||
FinallyProcessor fproc = new FinallyProcessor(varproc);
|
||||
while (fproc.iterateGraph(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());
|
||||
|
||||
FinallyProcessor fProc = new FinallyProcessor(md, varProc);
|
||||
while (fProc.iterateGraph(cl, mt, root, 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
|
||||
DomHelper.removeSynchronizedHandler(root);
|
||||
|
||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
||||
// System.out.println(graph.toString());
|
||||
|
||||
// LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
||||
|
||||
SequenceHelper.condenseSequences(root);
|
||||
|
||||
ClearStructHelper.clearStatements(root);
|
||||
|
||||
ExprProcessor proc = new ExprProcessor();
|
||||
ExprProcessor proc = new ExprProcessor(md, varProc);
|
||||
proc.processStatement(root, cl);
|
||||
|
||||
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
||||
// System.out.println(graph.toString());
|
||||
SequenceHelper.condenseSequences(root);
|
||||
|
||||
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
||||
StackVarsProcessor stackProc = new StackVarsProcessor();
|
||||
|
||||
while (true) {
|
||||
StackVarsProcessor stackproc = new StackVarsProcessor();
|
||||
stackproc.simplifyStackVars(root, mt, cl);
|
||||
|
||||
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
||||
|
||||
varproc.setVarVersions(root);
|
||||
|
||||
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
||||
|
||||
if (!new PPandMMHelper().findPPandMM(root)) {
|
||||
break;
|
||||
}
|
||||
do {
|
||||
stackProc.simplifyStackVars(root, mt, cl);
|
||||
varProc.setVarVersions(root);
|
||||
}
|
||||
while (new PPandMMHelper().findPPandMM(root));
|
||||
|
||||
while (true) {
|
||||
|
||||
LabelHelper.cleanUpEdges(root);
|
||||
|
||||
while (true) {
|
||||
|
||||
do {
|
||||
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 (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
|
||||
|
||||
SequenceHelper.condenseSequences(root);
|
||||
|
||||
StackVarsProcessor stackproc = new StackVarsProcessor();
|
||||
stackproc.simplifyStackVars(root, mt, cl);
|
||||
|
||||
varproc.setVarVersions(root);
|
||||
stackProc.simplifyStackVars(root, mt, cl);
|
||||
varProc.setVarVersions(root);
|
||||
}
|
||||
}
|
||||
|
||||
LabelHelper.identifyLabels(root);
|
||||
|
||||
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
||||
|
||||
if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {
|
||||
continue;
|
||||
}
|
||||
@ -225,16 +172,16 @@ public class MethodProcessorThread implements Runnable {
|
||||
}
|
||||
|
||||
// FIXME: !!
|
||||
// if(!EliminateLoopsHelper.eliminateLoops(root)) {
|
||||
// break;
|
||||
// }
|
||||
//if(!EliminateLoopsHelper.eliminateLoops(root)) {
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
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
|
||||
// FIXME: new edge type needed
|
||||
@ -242,8 +189,6 @@ public class MethodProcessorThread implements Runnable {
|
||||
|
||||
mt.releaseResources();
|
||||
|
||||
// System.out.println("++++++++++++++++++++++/// \r\n"+root.toJava());
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -253,7 +198,7 @@ public class MethodProcessorThread implements Runnable {
|
||||
return root;
|
||||
}
|
||||
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
package org.jetbrains.java.decompiler.main.rels;
|
||||
|
||||
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.stats.RootStatement;
|
||||
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 java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class MethodWrapper {
|
||||
|
||||
public RootStatement root;
|
||||
|
||||
public VarProcessor varproc;
|
||||
|
||||
public StructMethod methodStruct;
|
||||
|
||||
public CounterContainer counter;
|
||||
public final RootStatement root;
|
||||
public final VarProcessor varproc;
|
||||
public final StructMethod methodStruct;
|
||||
public final CounterContainer counter;
|
||||
public final Set<String> setOuterVarNames = new HashSet<>();
|
||||
|
||||
public DirectGraph graph;
|
||||
|
||||
public List<VarVersionPaar> signatureFields;
|
||||
|
||||
public List<VarVersionPair> synthParameters;
|
||||
public boolean decompiledWithErrors;
|
||||
|
||||
public HashSet<String> setOuterVarNames = new HashSet<String>();
|
||||
|
||||
public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {
|
||||
this.root = root;
|
||||
this.varproc = varproc;
|
||||
@ -54,9 +33,13 @@ public class MethodWrapper {
|
||||
|
||||
public DirectGraph getOrBuildGraph() {
|
||||
if (graph == null && root != null) {
|
||||
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
||||
graph = flatthelper.buildDirectGraph(root);
|
||||
graph = new FlattenStatementsHelper().buildDirectGraph(root);
|
||||
}
|
||||
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-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.
|
||||
*/
|
||||
// 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.rels;
|
||||
|
||||
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.sforms.DirectGraph;
|
||||
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.gen.MethodDescriptor;
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class NestedMemberAccess {
|
||||
|
||||
private static final int METHOD_ACCESS_NORMAL = 1;
|
||||
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 enum MethodAccess {NORMAL, FIELD_GET, FIELD_SET, METHOD, FUNCTION}
|
||||
|
||||
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) {
|
||||
@ -67,13 +47,13 @@ public class NestedMemberAccess {
|
||||
computeMethodTypes(nd);
|
||||
}
|
||||
|
||||
for (MethodWrapper method : node.wrapper.getMethods()) {
|
||||
for (MethodWrapper method : node.getWrapper().getMethods()) {
|
||||
computeMethodType(node, method);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeMethodType(ClassNode node, MethodWrapper method) {
|
||||
int type = METHOD_ACCESS_NORMAL;
|
||||
MethodAccess type = MethodAccess.NORMAL;
|
||||
|
||||
if (method.root != null) {
|
||||
DirectGraph graph = method.getOrBuildGraph();
|
||||
@ -91,7 +71,7 @@ public class NestedMemberAccess {
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -104,7 +84,7 @@ public class NestedMemberAccess {
|
||||
if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
|
||||
if (fexpr.isStatic() ||
|
||||
(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) {
|
||||
// this or final variable
|
||||
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;
|
||||
case Exprent.EXPRENT_INVOCATION:
|
||||
type = METHOD_ACCESS_METHOD;
|
||||
type = MethodAccess.METHOD;
|
||||
break;
|
||||
case Exprent.EXPRENT_ASSIGNMENT:
|
||||
AssignmentExprent asexpr = (AssignmentExprent)exprCore;
|
||||
@ -131,7 +121,7 @@ public class NestedMemberAccess {
|
||||
if (fexpras.isStatic() ||
|
||||
(fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
|
||||
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 = METHOD_ACCESS_NORMAL;
|
||||
type = MethodAccess.NORMAL;
|
||||
|
||||
InvocationExprent invexpr = (InvocationExprent)exprCore;
|
||||
|
||||
if ((invexpr.isStatic() && invexpr.getLstParameters().size() == parcount) ||
|
||||
(!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR
|
||||
boolean isStatic = invexpr.isStatic();
|
||||
if ((isStatic && invexpr.getLstParameters().size() == parcount) ||
|
||||
(!isStatic && invexpr.getInstance().type == Exprent.EXPRENT_VAR
|
||||
&& ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount - 1)) {
|
||||
|
||||
boolean equalpars = true;
|
||||
|
||||
int index = isStatic ? 0 : 1;
|
||||
for (int i = 0; i < invexpr.getLstParameters().size(); i++) {
|
||||
Exprent parexpr = invexpr.getLstParameters().get(i);
|
||||
if (parexpr.type != Exprent.EXPRENT_VAR ||
|
||||
((VarExprent)parexpr).getIndex() != i + (invexpr.isStatic() ? 0 : 1)) {
|
||||
if (parexpr.type != Exprent.EXPRENT_VAR || ((VarExprent)parexpr).getIndex() != index) {
|
||||
equalpars = false;
|
||||
break;
|
||||
}
|
||||
index += mtdesc.params[i + (isStatic ? 0 : 1)].stackSize;
|
||||
}
|
||||
|
||||
if (equalpars) {
|
||||
type = METHOD_ACCESS_METHOD;
|
||||
type = MethodAccess.METHOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,10 +179,10 @@ public class NestedMemberAccess {
|
||||
if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
|
||||
|
||||
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 &&
|
||||
((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);
|
||||
}
|
||||
else {
|
||||
@ -220,7 +211,7 @@ public class NestedMemberAccess {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MethodWrapper meth : node.wrapper.getMethods()) {
|
||||
for (MethodWrapper meth : node.getWrapper().getMethods()) {
|
||||
|
||||
if (meth.root != null) {
|
||||
|
||||
@ -228,8 +219,8 @@ public class NestedMemberAccess {
|
||||
|
||||
DirectGraph graph = meth.getOrBuildGraph();
|
||||
|
||||
HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
|
||||
LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
|
||||
HashSet<DirectNode> setVisited = new HashSet<>();
|
||||
LinkedList<DirectNode> stack = new LinkedList<>();
|
||||
stack.add(graph.first);
|
||||
|
||||
while (!stack.isEmpty()) { // TODO: replace with interface iterator?
|
||||
@ -256,9 +247,7 @@ public class NestedMemberAccess {
|
||||
}
|
||||
}
|
||||
|
||||
for (DirectNode ndx : nd.succs) {
|
||||
stack.add(ndx);
|
||||
}
|
||||
stack.addAll(nd.succs);
|
||||
}
|
||||
|
||||
if (replaced) {
|
||||
@ -323,12 +312,11 @@ public class NestedMemberAccess {
|
||||
}
|
||||
|
||||
private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
|
||||
|
||||
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassname());
|
||||
|
||||
MethodWrapper methsource = null;
|
||||
if (node != null && node.wrapper != null) {
|
||||
methsource = node.wrapper.getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
|
||||
if (node != null && node.getWrapper() != null) {
|
||||
methsource = node.getWrapper().getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
|
||||
}
|
||||
|
||||
if (methsource == null || !mapMethodType.containsKey(methsource)) {
|
||||
@ -343,10 +331,10 @@ public class NestedMemberAccess {
|
||||
return null;
|
||||
}
|
||||
|
||||
int type = mapMethodType.get(methsource);
|
||||
MethodAccess type = mapMethodType.get(methsource);
|
||||
|
||||
// // FIXME: impossible case. METHOD_ACCESS_NORMAL is not saved in the map
|
||||
// if(type == METHOD_ACCESS_NORMAL) {
|
||||
// // FIXME: impossible case. MethodAccess.NORMAL is not saved in the map
|
||||
// if(type == MethodAccess.NORMAL) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
@ -360,11 +348,11 @@ public class NestedMemberAccess {
|
||||
Exprent retexprent = null;
|
||||
|
||||
switch (type) {
|
||||
case METHOD_ACCESS_FIELD_GET:
|
||||
case FIELD_GET:
|
||||
ExitExprent exsource = (ExitExprent)source;
|
||||
if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
|
||||
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)) {
|
||||
VarNamesCollector vnc = new VarNamesCollector();
|
||||
@ -375,8 +363,8 @@ public class NestedMemberAccess {
|
||||
}
|
||||
|
||||
int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
||||
VarExprent ret = new VarExprent(index, var.getVartype(), methdest.varproc);
|
||||
methdest.varproc.setVarName(new VarVersionPaar(index, 0), varname);
|
||||
VarExprent ret = new VarExprent(index, var.getVarType(), methdest.varproc);
|
||||
methdest.varproc.setVarName(new VarVersionPair(index, 0), varname);
|
||||
|
||||
retexprent = ret;
|
||||
}
|
||||
@ -388,7 +376,7 @@ public class NestedMemberAccess {
|
||||
retexprent = ret;
|
||||
}
|
||||
break;
|
||||
case METHOD_ACCESS_FIELD_SET:
|
||||
case FIELD_SET:
|
||||
AssignmentExprent ret;
|
||||
if (source.type == Exprent.EXPRENT_EXIT) {
|
||||
ExitExprent extex = (ExitExprent)source;
|
||||
@ -406,9 +394,17 @@ public class NestedMemberAccess {
|
||||
ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(1));
|
||||
fexpr.replaceExprent(fexpr.getInstance(), invexpr.getLstParameters().get(0));
|
||||
}
|
||||
|
||||
// do not use copied bytecodes
|
||||
ret.getLeft().bytecode = null;
|
||||
ret.getRight().bytecode = null;
|
||||
|
||||
retexprent = ret;
|
||||
break;
|
||||
case METHOD_ACCESS_METHOD:
|
||||
case FUNCTION:
|
||||
retexprent = replaceFunction(invexpr, source);
|
||||
break;
|
||||
case METHOD:
|
||||
if (source.type == Exprent.EXPRENT_EXIT) {
|
||||
source = ((ExitExprent)source).getValue();
|
||||
}
|
||||
@ -430,6 +426,10 @@ public class NestedMemberAccess {
|
||||
|
||||
|
||||
if (retexprent != null) {
|
||||
// preserve original bytecodes
|
||||
retexprent.bytecode = null;
|
||||
retexprent.addBytecodeOffsets(invexpr.bytecode);
|
||||
|
||||
// hide synthetic access method
|
||||
boolean hide = true;
|
||||
|
||||
@ -440,10 +440,31 @@ public class NestedMemberAccess {
|
||||
}
|
||||
}
|
||||
if (hide) {
|
||||
node.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
|
||||
node.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
|
||||
}
|
||||
}
|
||||
|
||||
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-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.
|
||||
*/
|
||||
// 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.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.ControlFlowGraph;
|
||||
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
||||
@ -26,12 +13,12 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class DeadCodeHelper {
|
||||
public final class DeadCodeHelper {
|
||||
|
||||
public static void removeDeadBlocks(ControlFlowGraph graph) {
|
||||
|
||||
LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
|
||||
HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>();
|
||||
LinkedList<BasicBlock> stack = new LinkedList<>();
|
||||
HashSet<BasicBlock> setStacked = new HashSet<>();
|
||||
|
||||
stack.add(graph.getFirst());
|
||||
setStacked.add(graph.getFirst());
|
||||
@ -39,7 +26,7 @@ public class DeadCodeHelper {
|
||||
while (!stack.isEmpty()) {
|
||||
BasicBlock block = stack.removeFirst();
|
||||
|
||||
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
|
||||
List<BasicBlock> lstSuccs = new ArrayList<>(block.getSuccs());
|
||||
lstSuccs.addAll(block.getSuccExceptions());
|
||||
|
||||
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);
|
||||
|
||||
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() &&
|
||||
(!setExits.contains(block) || block.getPreds().size() == 1)) {
|
||||
@ -109,15 +96,15 @@ public class DeadCodeHelper {
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds());
|
||||
HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs());
|
||||
HashSet<BasicBlock> setPreds = new HashSet<>(block.getPreds());
|
||||
HashSet<BasicBlock> setSuccs = new HashSet<>(block.getSuccs());
|
||||
|
||||
// collect common exception ranges of predecessors and successors
|
||||
HashSet<BasicBlock> setCommonExceptionHandlers = null;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (BasicBlock pred : i == 0 ? setPreds : setSuccs) {
|
||||
if (setCommonExceptionHandlers == null) {
|
||||
setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions());
|
||||
setCommonExceptionHandlers = new HashSet<>(pred.getSuccExceptions());
|
||||
}
|
||||
else {
|
||||
setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
|
||||
@ -159,7 +146,7 @@ public class DeadCodeHelper {
|
||||
BasicBlock pred = block.getPreds().get(0);
|
||||
pred.removeSuccessor(block);
|
||||
|
||||
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
|
||||
List<BasicBlock> lstSuccs = new ArrayList<>(block.getSuccs());
|
||||
for (BasicBlock succ : lstSuccs) {
|
||||
block.removeSuccessor(succ);
|
||||
pred.addSuccessor(succ);
|
||||
@ -205,13 +192,13 @@ public class DeadCodeHelper {
|
||||
|
||||
public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) {
|
||||
|
||||
HashSet<BasicBlock> marked = new HashSet<BasicBlock>();
|
||||
HashSet<BasicBlock> marked = new HashSet<>();
|
||||
|
||||
if (block == dom) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
|
||||
LinkedList<BasicBlock> lstNodes = new LinkedList<>();
|
||||
lstNodes.add(block);
|
||||
|
||||
while (!lstNodes.isEmpty()) {
|
||||
@ -230,14 +217,14 @@ public class DeadCodeHelper {
|
||||
|
||||
for (int i = 0; i < node.getPreds().size(); i++) {
|
||||
BasicBlock pred = node.getPreds().get(i);
|
||||
if (!marked.contains(pred) && pred != dom) {
|
||||
if (pred != dom && !marked.contains(pred)) {
|
||||
lstNodes.add(pred);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.getPredExceptions().size(); i++) {
|
||||
BasicBlock pred = node.getPredExceptions().get(i);
|
||||
if (!marked.contains(pred) && pred != dom) {
|
||||
if (pred != dom && !marked.contains(pred)) {
|
||||
lstNodes.add(pred);
|
||||
}
|
||||
}
|
||||
@ -252,7 +239,7 @@ public class DeadCodeHelper {
|
||||
Instruction instr = block.getLastInstruction();
|
||||
|
||||
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) {
|
||||
|
||||
BasicBlock exit = graph.getLast();
|
||||
for (BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) {
|
||||
for (BasicBlock block : new HashSet<>(exit.getPreds())) {
|
||||
exit.removePredecessor(block);
|
||||
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) {
|
||||
|
||||
for (BasicBlock block : graph.getBlocks()) {
|
||||
@ -311,8 +447,8 @@ public class DeadCodeHelper {
|
||||
|
||||
if (!block.getPreds().isEmpty()) {
|
||||
|
||||
HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>();
|
||||
HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>();
|
||||
HashSet<BasicBlock> setPredHandlersUnion = new HashSet<>();
|
||||
HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<>();
|
||||
|
||||
boolean firstpred = true;
|
||||
for (BasicBlock pred : block.getPreds()) {
|
||||
@ -328,7 +464,9 @@ public class DeadCodeHelper {
|
||||
}
|
||||
|
||||
// add exception ranges from predecessors
|
||||
setPredHandlersIntersection.removeAll(block.getSuccExceptions());
|
||||
for (BasicBlock basicBlock : block.getSuccExceptions()) {
|
||||
setPredHandlersIntersection.remove(basicBlock);
|
||||
}
|
||||
BasicBlock predecessor = block.getPreds().get(0);
|
||||
|
||||
for (BasicBlock handler : setPredHandlersIntersection) {
|
||||
@ -339,7 +477,7 @@ public class DeadCodeHelper {
|
||||
}
|
||||
|
||||
// remove redundant ranges
|
||||
HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions());
|
||||
HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<>(block.getSuccExceptions());
|
||||
setRangesToBeRemoved.removeAll(setPredHandlersUnion);
|
||||
|
||||
for (BasicBlock handler : setRangesToBeRemoved) {
|
||||
@ -369,7 +507,7 @@ public class DeadCodeHelper {
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
ExceptionRangeCFG range = graph.getExceptionRange(succ, block);
|
||||
|
||||
@ -416,6 +554,7 @@ public class DeadCodeHelper {
|
||||
|
||||
if (sameRanges) {
|
||||
seq.addSequence(next.getSeq());
|
||||
block.getInstrOldOffsets().addAll(next.getInstrOldOffsets());
|
||||
next.getSeq().clear();
|
||||
|
||||
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-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.
|
||||
*/
|
||||
// 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.modules.decompiler.stats.RootStatement;
|
||||
@ -21,11 +7,11 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
|
||||
import java.util.LinkedList;
|
||||
|
||||
|
||||
public class ClearStructHelper {
|
||||
public final class ClearStructHelper {
|
||||
|
||||
public static void clearStatements(RootStatement root) {
|
||||
|
||||
LinkedList<Statement> stack = new LinkedList<Statement>();
|
||||
LinkedList<Statement> stack = new LinkedList<>();
|
||||
stack.add(root);
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
|
@ -1,29 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.code.CodeConstants;
|
||||
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.VarType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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 bufferClass = "java/lang/StringBuffer";
|
||||
@ -52,6 +42,12 @@ public class ConcatenationHelper {
|
||||
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) {
|
||||
@ -60,7 +56,7 @@ public class ConcatenationHelper {
|
||||
|
||||
|
||||
// iterate in depth, collecting possible operands
|
||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
||||
List<Exprent> lstOperands = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
|
||||
@ -104,7 +100,7 @@ public class ConcatenationHelper {
|
||||
}
|
||||
|
||||
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
|
||||
@ -125,20 +121,69 @@ public class ConcatenationHelper {
|
||||
lstOperands.set(i, rep);
|
||||
}
|
||||
}
|
||||
return createConcatExprent(lstOperands, expr.bytecode);
|
||||
}
|
||||
|
||||
private static Exprent createConcatExprent(List<Exprent> lstOperands, Set<Integer> bytecode) {
|
||||
// build exprent to return
|
||||
Exprent func = lstOperands.get(0);
|
||||
|
||||
for (int i = 1; i < lstOperands.size(); i++) {
|
||||
List<Exprent> lstTmp = new ArrayList<Exprent>();
|
||||
lstTmp.add(func);
|
||||
lstTmp.add(lstOperands.get(i));
|
||||
func = new FunctionExprent(FunctionExprent.FUNCTION_STRCONCAT, lstTmp);
|
||||
func = new FunctionExprent(FunctionExprent.FUNCTION_STR_CONCAT, Arrays.asList(func, lstOperands.get(i)), bytecode);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if ("append".equals(expr.getName())) {
|
||||
@ -167,13 +212,9 @@ public class ConcatenationHelper {
|
||||
}
|
||||
|
||||
private static boolean isNewConcat(NewExprent expr, VarType cltype) {
|
||||
|
||||
if (expr.getNewtype().equals(cltype)) {
|
||||
if (expr.getNewType().equals(cltype)) {
|
||||
VarType[] params = expr.getConstructor().getDescriptor().params;
|
||||
if (params.length == 0 || (params.length == 1 &&
|
||||
params[0].equals(VarType.VARTYPE_STRING))) {
|
||||
return true;
|
||||
}
|
||||
return params.length == 0 || params.length == 1 && params[0].equals(VarType.VARTYPE_STRING);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1,33 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.modules.decompiler.exps.Exprent;
|
||||
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;
|
||||
|
||||
for (Statement stat : lst) {
|
||||
@ -37,7 +26,7 @@ public class DecHelper {
|
||||
intersection = setNew;
|
||||
}
|
||||
else {
|
||||
HashSet<Statement> interclone = new HashSet<Statement>(intersection);
|
||||
HashSet<Statement> interclone = new HashSet<>(intersection);
|
||||
interclone.removeAll(setNew);
|
||||
|
||||
intersection.retainAll(setNew);
|
||||
@ -66,7 +55,7 @@ public class DecHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isChoiceStatement(Statement head, List<Statement> lst) {
|
||||
public static boolean isChoiceStatement(Statement head, List<? super Statement> lst) {
|
||||
|
||||
Statement post = null;
|
||||
|
||||
@ -159,7 +148,7 @@ public class DecHelper {
|
||||
if (head == statd) {
|
||||
return false;
|
||||
}
|
||||
if (!setDest.contains(statd) && post != statd) {
|
||||
if (post != statd && !setDest.contains(statd)) {
|
||||
if (post != null) {
|
||||
return false;
|
||||
}
|
||||
@ -194,25 +183,17 @@ public class DecHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static HashSet<Statement> getUniquePredExceptions(Statement head) {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
public static Set<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);
|
||||
return setHandlers;
|
||||
}
|
||||
|
||||
public static List<Exprent> copyExprentList(List<Exprent> lst) {
|
||||
List<Exprent> ret = new ArrayList<Exprent>();
|
||||
public static List<Exprent> copyExprentList(List<? extends Exprent> lst) {
|
||||
List<Exprent> ret = new ArrayList<>();
|
||||
for (Exprent expr : lst) {
|
||||
ret.add(expr.copy());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.code.cfg.BasicBlock;
|
||||
@ -30,12 +16,12 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class DomHelper {
|
||||
public final class DomHelper {
|
||||
|
||||
|
||||
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();
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
@ -46,8 +32,7 @@ public class DomHelper {
|
||||
// head statement
|
||||
Statement firstst = stats.getWithKey(firstblock.id);
|
||||
// dummy exit statement
|
||||
Statement dummyexit = new Statement();
|
||||
dummyexit.type = Statement.TYPE_DUMMYEXIT;
|
||||
DummyExitStatement dummyexit = new DummyExitStatement();
|
||||
|
||||
Statement general;
|
||||
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) {
|
||||
|
||||
HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<Statement, FastFixedSet<Statement>>();
|
||||
HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<>();
|
||||
|
||||
StrongConnectivityHelper schelper = new StrongConnectivityHelper(container);
|
||||
List<List<Statement>> components = schelper.getComponents();
|
||||
|
||||
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();
|
||||
setFlagNodes.setAllElements();
|
||||
@ -177,26 +162,22 @@ public class DomHelper {
|
||||
}
|
||||
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!
|
||||
|
||||
final HashMap<Integer, Integer> mapSortOrder = new HashMap<Integer, Integer>();
|
||||
final HashMap<Integer, Integer> mapSortOrder = new HashMap<>();
|
||||
for (int i = 0; i < lstRevPost.size(); i++) {
|
||||
mapSortOrder.put(lstRevPost.get(i).id, i);
|
||||
}
|
||||
|
||||
for (Statement st : lstStats) {
|
||||
|
||||
List<Integer> lstPosts = new ArrayList<Integer>();
|
||||
List<Integer> lstPosts = new ArrayList<>();
|
||||
for (Statement stt : lists.get(st)) {
|
||||
lstPosts.add(stt.id);
|
||||
}
|
||||
|
||||
Collections.sort(lstPosts, new Comparator<Integer>() {
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return mapSortOrder.get(o1).compareTo(mapSortOrder.get(o2));
|
||||
}
|
||||
});
|
||||
lstPosts.sort(Comparator.comparing(mapSortOrder::get));
|
||||
|
||||
if (lstPosts.size() > 1 && lstPosts.get(0).intValue() == st.id) {
|
||||
lstPosts.add(lstPosts.remove(0));
|
||||
@ -212,11 +193,17 @@ public class DomHelper {
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
||||
LabelHelper.lowContinueLabels(root, new HashSet<>());
|
||||
|
||||
SequenceHelper.condenseSequences(root);
|
||||
root.buildMonitorFlags();
|
||||
@ -286,7 +273,7 @@ public class DomHelper {
|
||||
SynchronizedStatement sync = new SynchronizedStatement(current, ca.getFirst(), ca.getHandler());
|
||||
sync.setAllParent();
|
||||
|
||||
for (StatEdge edge : new HashSet<StatEdge>(ca.getLabelEdges())) {
|
||||
for (StatEdge edge : new HashSet<>(ca.getLabelEdges())) {
|
||||
sync.addLabeledEdge(edge);
|
||||
}
|
||||
|
||||
@ -356,7 +343,7 @@ public class DomHelper {
|
||||
// DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
|
||||
// } catch(Exception ex) {ex.printStackTrace();}
|
||||
|
||||
mapExtPost = new HashMap<Integer, Set<Integer>>();
|
||||
mapExtPost = new HashMap<>();
|
||||
mapRefreshed = true;
|
||||
}
|
||||
|
||||
@ -377,7 +364,7 @@ public class DomHelper {
|
||||
Statement stat = findGeneralStatement(general, forceall, mapExtPost);
|
||||
|
||||
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) {
|
||||
// replace general purpose statement with simple one
|
||||
@ -387,7 +374,7 @@ public class DomHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
mapExtPost = new HashMap<Integer, Set<Integer>>();
|
||||
mapExtPost = new HashMap<>();
|
||||
mapRefreshed = true;
|
||||
reducibility = 0;
|
||||
}
|
||||
@ -408,7 +395,7 @@ public class DomHelper {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
mapExtPost = new HashMap<Integer, Set<Integer>>();
|
||||
mapExtPost = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,13 +413,13 @@ public class DomHelper {
|
||||
}
|
||||
|
||||
if (forceall) {
|
||||
vbPost = new VBStyleCollection<List<Integer>, Integer>();
|
||||
vbPost = new VBStyleCollection<>();
|
||||
List<Statement> lstAll = stat.getPostReversePostOrderList();
|
||||
|
||||
for (Statement st : lstAll) {
|
||||
Set<Integer> set = mapExtPost.get(st.id);
|
||||
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) {
|
||||
List<Integer> lst = vbPost.getWithKey(id);
|
||||
if (lst == null) {
|
||||
vbPost.addWithKey(lst = new ArrayList<Integer>(), id);
|
||||
vbPost.addWithKey(lst = new ArrayList<>(), id);
|
||||
}
|
||||
lst.add(id);
|
||||
}
|
||||
@ -466,14 +453,12 @@ public class DomHelper {
|
||||
|
||||
Set<Integer> setExtPosts = mapExtPost.get(headid);
|
||||
|
||||
for (int i = 0; i < posts.size(); i++) {
|
||||
|
||||
Integer postid = posts.get(i);
|
||||
if (!postid.equals(headid) && !setExtPosts.contains(postid)) {
|
||||
for (Integer postId : posts) {
|
||||
if (!postId.equals(headid) && !setExtPosts.contains(postId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Statement post = stats.getWithKey(postid);
|
||||
Statement post = stats.getWithKey(postId);
|
||||
|
||||
if (post == null) { // possible in case of an inherited postdominance set
|
||||
continue;
|
||||
@ -481,11 +466,11 @@ public class DomHelper {
|
||||
|
||||
boolean same = (post == head);
|
||||
|
||||
HashSet<Statement> setNodes = new HashSet<Statement>();
|
||||
HashSet<Statement> setPreds = new HashSet<Statement>();
|
||||
HashSet<Statement> setNodes = new HashSet<>();
|
||||
HashSet<Statement> setPreds = new HashSet<>();
|
||||
|
||||
// collect statement nodes
|
||||
HashSet<Statement> setHandlers = new HashSet<Statement>();
|
||||
HashSet<Statement> setHandlers = new HashSet<>();
|
||||
setHandlers.add(head);
|
||||
while (true) {
|
||||
|
||||
@ -503,7 +488,7 @@ public class DomHelper {
|
||||
}
|
||||
|
||||
if (addhd) {
|
||||
LinkedList<Statement> lstStack = new LinkedList<Statement>();
|
||||
LinkedList<Statement> lstStack = new LinkedList<>();
|
||||
lstStack.add(handler);
|
||||
|
||||
while (!lstStack.isEmpty()) {
|
||||
@ -552,14 +537,14 @@ public class DomHelper {
|
||||
|
||||
// build statement and return
|
||||
if (excok) {
|
||||
Statement res = null;
|
||||
Statement res;
|
||||
|
||||
setPreds.removeAll(setNodes);
|
||||
if (setPreds.size() == 0) {
|
||||
if ((setNodes.size() > 1 ||
|
||||
head.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).contains(head))
|
||||
&& setNodes.size() < stats.size()) {
|
||||
if (checkSynchronizedCompleteness(head, setNodes)) {
|
||||
if (checkSynchronizedCompleteness(setNodes)) {
|
||||
res = new GeneralStatement(head, setNodes, same ? null : post);
|
||||
stat.collapseNodesToStatement(res);
|
||||
|
||||
@ -574,8 +559,7 @@ public class DomHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean checkSynchronizedCompleteness(Statement head, HashSet<Statement> setNodes) {
|
||||
|
||||
private static boolean checkSynchronizedCompleteness(Set<Statement> setNodes) {
|
||||
// check exit nodes
|
||||
for (Statement stat : setNodes) {
|
||||
if (stat.isMonitorEnter()) {
|
||||
@ -617,26 +601,21 @@ public class DomHelper {
|
||||
|
||||
// update the postdominator map
|
||||
if (!mapExtPost.isEmpty()) {
|
||||
HashSet<Integer> setOldNodes = new HashSet<Integer>();
|
||||
HashSet<Integer> setOldNodes = new HashSet<>();
|
||||
for (Statement old : result.getStats()) {
|
||||
setOldNodes.add(old.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);
|
||||
|
||||
int oldsize = set.size();
|
||||
set.removeAll(setOldNodes);
|
||||
|
||||
if (setOldNodes.contains(key)) {
|
||||
Set<Integer> setNew = mapExtPost.get(newid);
|
||||
if (setNew == null) {
|
||||
mapExtPost.put(newid, setNew = new HashSet<Integer>());
|
||||
}
|
||||
setNew.addAll(set);
|
||||
|
||||
mapExtPost.computeIfAbsent(newid, k -> new HashSet<>()).addAll(set);
|
||||
mapExtPost.remove(key);
|
||||
}
|
||||
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-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.
|
||||
*/
|
||||
// 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.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.Exprent;
|
||||
import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
|
||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ExitHelper {
|
||||
|
||||
|
||||
public final class ExitHelper {
|
||||
public static boolean condenseExits(RootStatement root) {
|
||||
|
||||
int changed = integrateExits(root);
|
||||
|
||||
if (changed > 0) {
|
||||
|
||||
cleanUpUnreachableBlocks(root);
|
||||
|
||||
SequenceHelper.condenseSequences(root);
|
||||
}
|
||||
|
||||
return (changed > 0);
|
||||
}
|
||||
|
||||
|
||||
private static void cleanUpUnreachableBlocks(Statement stat) {
|
||||
|
||||
boolean found;
|
||||
do {
|
||||
|
||||
found = false;
|
||||
|
||||
for (int i = 0; i < stat.getStats().size(); i++) {
|
||||
|
||||
Statement st = stat.getStats().get(i);
|
||||
|
||||
cleanUpUnreachableBlocks(st);
|
||||
@ -71,7 +47,7 @@ public class ExitHelper {
|
||||
set.remove(secondlast);
|
||||
|
||||
if (set.isEmpty()) {
|
||||
last.setExprents(new ArrayList<Exprent>());
|
||||
last.setExprents(new ArrayList<>());
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -83,16 +59,12 @@ public class ExitHelper {
|
||||
while (found);
|
||||
}
|
||||
|
||||
|
||||
private static int integrateExits(Statement stat) {
|
||||
|
||||
int ret = 0;
|
||||
Statement dest = null;
|
||||
Statement dest;
|
||||
|
||||
if (stat.getExprents() == null) {
|
||||
|
||||
while (true) {
|
||||
|
||||
int changed = 0;
|
||||
|
||||
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) {
|
||||
case 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()));
|
||||
ifst.getFirst().removeSuccessor(ifedge);
|
||||
StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
|
||||
ifst.getFirst().addSuccessor(newedge);
|
||||
ifst.setIfEdge(newedge);
|
||||
ifst.setIfstat(bstat);
|
||||
ifst.getStats().addWithKey(bstat, bstat.id);
|
||||
bstat.setParent(ifst);
|
||||
|
||||
ifst.getFirst().removeSuccessor(ifedge);
|
||||
StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
|
||||
ifst.getFirst().addSuccessor(newedge);
|
||||
ifst.setIfEdge(newedge);
|
||||
ifst.setIfstat(bstat);
|
||||
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;
|
||||
}
|
||||
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>());
|
||||
// do it by hand
|
||||
for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
|
||||
|
||||
block.removePredecessor(prededge);
|
||||
prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, stat);
|
||||
stat.addPredecessor(prededge);
|
||||
|
||||
stat.addLabeledEdge(prededge);
|
||||
}
|
||||
|
||||
|
||||
stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, bstat));
|
||||
|
||||
for (StatEdge edge : dest.getAllPredecessorEdges()) {
|
||||
@ -202,11 +169,9 @@ public class ExitHelper {
|
||||
}
|
||||
|
||||
private static Statement isExitEdge(StatEdge edge) {
|
||||
|
||||
Statement dest = edge.getDestination();
|
||||
|
||||
if (edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK
|
||||
&& edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
|
||||
if (edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK && edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
|
||||
List<Exprent> data = dest.getExprents();
|
||||
|
||||
if (data != null && data.size() == 1) {
|
||||
@ -220,7 +185,6 @@ public class ExitHelper {
|
||||
}
|
||||
|
||||
private static boolean isOnlyEdge(StatEdge edge) {
|
||||
|
||||
Statement stat = edge.getDestination();
|
||||
|
||||
for (StatEdge ed : stat.getAllPredecessorEdges()) {
|
||||
@ -243,11 +207,10 @@ public class ExitHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean removeRedundantReturns(RootStatement root) {
|
||||
public static void removeRedundantReturns(RootStatement root) {
|
||||
DummyExitStatement dummyExit = root.getDummyExit();
|
||||
|
||||
boolean res = false;
|
||||
|
||||
for (StatEdge edge : root.getDummyExit().getAllPredecessorEdges()) {
|
||||
for (StatEdge edge : dummyExit.getAllPredecessorEdges()) {
|
||||
if (!edge.explicit) {
|
||||
Statement source = edge.getSource();
|
||||
List<Exprent> lstExpr = source.getExprents();
|
||||
@ -255,91 +218,14 @@ public class ExitHelper {
|
||||
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) {
|
||||
if (ex.getExitType() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
|
||||
// remove redundant return
|
||||
dummyExit.addBytecodeOffsets(ex.bytecode);
|
||||
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-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.
|
||||
*/
|
||||
// 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.modules.decompiler;
|
||||
|
||||
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.cfg.BasicBlock;
|
||||
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.modules.decompiler.exps.*;
|
||||
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.gen.MethodDescriptor;
|
||||
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 org.jetbrains.java.decompiler.util.SortUtil;
|
||||
import org.jetbrains.java.decompiler.util.Util;
|
||||
|
||||
public class ExprProcessor implements CodeConstants {
|
||||
|
||||
public static final String UNDEFINED_TYPE_STRING = "<undefinedtype>";
|
||||
public static final String UNKNOWN_TYPE_STRING = "<unknown>";
|
||||
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 {
|
||||
|
||||
// mapConsts.put(new Integer(opc_i2l), new
|
||||
// Integer(FunctionExprent.FUNCTION_I2L));
|
||||
// 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));
|
||||
mapConsts.put(opc_arraylength, FunctionExprent.FUNCTION_ARRAY_LENGTH);
|
||||
mapConsts.put(opc_checkcast, FunctionExprent.FUNCTION_CAST);
|
||||
mapConsts.put(opc_instanceof, FunctionExprent.FUNCTION_INSTANCEOF);
|
||||
}
|
||||
|
||||
private static final VarType[] consts =
|
||||
new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS,
|
||||
VarType.VARTYPE_STRING};
|
||||
private static final VarType[] consts = {
|
||||
VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS, VarType.VARTYPE_STRING
|
||||
};
|
||||
|
||||
private static final VarType[] vartypes =
|
||||
new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT};
|
||||
private static final VarType[] varTypes = {
|
||||
VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT
|
||||
};
|
||||
|
||||
private static final VarType[] arrtypes =
|
||||
new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
|
||||
VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT};
|
||||
private static final VarType[] arrTypes = {
|
||||
VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
|
||||
VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT
|
||||
};
|
||||
|
||||
private static final int[] func1 =
|
||||
new int[]{FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
|
||||
FunctionExprent.FUNCTION_REM};
|
||||
private static final int[] func1 = {
|
||||
FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
|
||||
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 =
|
||||
new int[]{FunctionExprent.FUNCTION_SHL, FunctionExprent.FUNCTION_SHR, FunctionExprent.FUNCTION_USHR, FunctionExprent.FUNCTION_AND,
|
||||
FunctionExprent.FUNCTION_OR, FunctionExprent.FUNCTION_XOR};
|
||||
private static final int[] arrTypeIds = {
|
||||
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[] func3 =
|
||||
new int[]{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[] negIfs = {
|
||||
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 int[] func4 =
|
||||
new int[]{FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL,
|
||||
FunctionExprent.FUNCTION_DCMPG};
|
||||
private static final String[] typeNames = {"byte", "char", "double", "float", "int", "long", "short", "boolean"};
|
||||
|
||||
private static final int[] func5 =
|
||||
new int[]{IfExprent.IF_EQ, IfExprent.IF_NE, IfExprent.IF_LT, IfExprent.IF_GE, IfExprent.IF_GT, IfExprent.IF_LE};
|
||||
private final MethodDescriptor methodDescriptor;
|
||||
private final VarProcessor varProcessor;
|
||||
|
||||
private static final int[] func6 =
|
||||
new int[]{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 = 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 ExprProcessor(MethodDescriptor md, VarProcessor varProc) {
|
||||
methodDescriptor = md;
|
||||
varProcessor = varProc;
|
||||
}
|
||||
|
||||
public void processStatement(RootStatement root, StructClass cl) {
|
||||
|
||||
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
||||
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
||||
|
||||
// try {
|
||||
// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
|
||||
// } catch (Exception ex) {
|
||||
// ex.printStackTrace();
|
||||
// }
|
||||
|
||||
// collect finally entry points
|
||||
Set<String> setFinallyShortRangeEntryPoints = new HashSet<String>();
|
||||
Set<String> setFinallyShortRangeEntryPoints = new HashSet<>();
|
||||
for (List<FinallyPathWrapper> lst : dgraph.mapShortRangeFinallyPaths.values()) {
|
||||
for (FinallyPathWrapper finwrap : lst) {
|
||||
setFinallyShortRangeEntryPoints.add(finwrap.entry);
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> setFinallyLongRangeEntryPaths = new HashSet<String>();
|
||||
Set<String> setFinallyLongRangeEntryPaths = new HashSet<>();
|
||||
for (List<FinallyPathWrapper> lst : dgraph.mapLongRangeFinallyPaths.values()) {
|
||||
for (FinallyPathWrapper finwrap : lst) {
|
||||
setFinallyLongRangeEntryPaths.add(finwrap.source + "##" + finwrap.entry);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, VarExprent> mapCatch = new HashMap<String, VarExprent>();
|
||||
Map<String, VarExprent> mapCatch = new HashMap<>();
|
||||
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<LinkedList<String>> stackEntryPoint = new LinkedList<LinkedList<String>>();
|
||||
LinkedList<DirectNode> stack = new LinkedList<>();
|
||||
LinkedList<LinkedList<String>> stackEntryPoint = new LinkedList<>();
|
||||
|
||||
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());
|
||||
mapData.put(dgraph.first, map);
|
||||
|
||||
@ -222,13 +171,8 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
|
||||
if (isSuccessor) {
|
||||
|
||||
Map<String, PrimitiveExprsList> mapSucc = mapData.get(nd);
|
||||
if (mapSucc == null) {
|
||||
mapData.put(nd, mapSucc = new HashMap<String, PrimitiveExprsList>());
|
||||
}
|
||||
|
||||
LinkedList<String> ndentrypoints = new LinkedList<String>(entrypoints);
|
||||
Map<String, PrimitiveExprsList> mapSucc = mapData.computeIfAbsent(nd, k -> new HashMap<>());
|
||||
LinkedList<String> ndentrypoints = new LinkedList<>(entrypoints);
|
||||
|
||||
if (setFinallyLongRangeEntryPaths.contains(node.id + "##" + nd.id)) {
|
||||
ndentrypoints.addLast(node.id);
|
||||
@ -279,10 +223,14 @@ public class ExprProcessor implements CodeConstants {
|
||||
|
||||
private static PrimitiveExprsList copyVarExprents(PrimitiveExprsList data) {
|
||||
ExprentStack stack = data.getStack();
|
||||
copyEntries(stack);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void copyEntries(List<Exprent> stack) {
|
||||
for (int i = 0; i < stack.size(); i++) {
|
||||
stack.set(i, stack.get(i).copy());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
ConstantPool pool = cl.getPool();
|
||||
StructBootstrapMethodsAttribute bootstrap =
|
||||
(StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
||||
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
|
||||
|
||||
BasicBlock block = stat.getBlock();
|
||||
|
||||
@ -335,40 +282,47 @@ public class ExprProcessor implements CodeConstants {
|
||||
|
||||
Instruction instr = seq.getInstr(i);
|
||||
Integer bytecode_offset = block.getOldOffset(i);
|
||||
Set<Integer> bytecode_offsets = bytecode_offset >= 0 ? Collections.singleton(bytecode_offset) : null;
|
||||
|
||||
switch (instr.opcode) {
|
||||
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;
|
||||
case opc_bipush:
|
||||
case opc_sipush:
|
||||
pushEx(stack, exprlist, new ConstExprent(instr.getOperand(0), true));
|
||||
pushEx(stack, exprlist, new ConstExprent(instr.operand(0), true, bytecode_offsets));
|
||||
break;
|
||||
case opc_lconst_0:
|
||||
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;
|
||||
case opc_fconst_0:
|
||||
case opc_fconst_1:
|
||||
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;
|
||||
case opc_dconst_0:
|
||||
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;
|
||||
case opc_ldc:
|
||||
case opc_ldc_w:
|
||||
case opc_ldc2_w:
|
||||
PrimitiveConstant cn = pool.getPrimitiveConstant(instr.getOperand(0));
|
||||
pushEx(stack, exprlist, new ConstExprent(consts[cn.type - CONSTANT_Integer], cn.value));
|
||||
PooledConstant cn = pool.getConstant(instr.operand(0));
|
||||
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;
|
||||
case opc_iload:
|
||||
case opc_lload:
|
||||
case opc_fload:
|
||||
case opc_dload:
|
||||
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;
|
||||
case opc_iaload:
|
||||
case opc_laload:
|
||||
@ -389,17 +343,17 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_daload:
|
||||
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;
|
||||
case opc_istore:
|
||||
case opc_lstore:
|
||||
case opc_fstore:
|
||||
case opc_dstore:
|
||||
case opc_astore:
|
||||
Exprent top = stack.pop();
|
||||
int varindex = instr.getOperand(0);
|
||||
AssignmentExprent assign =
|
||||
new AssignmentExprent(new VarExprent(varindex, vartypes[instr.opcode - opc_istore], varProcessor), top);
|
||||
Exprent expr = stack.pop();
|
||||
int varindex = instr.operand(0);
|
||||
AssignmentExprent assign = new AssignmentExprent(
|
||||
new VarExprent(varindex, varTypes[instr.opcode - opc_istore], varProcessor, nextMeaningfulOffset(block, i)), expr, bytecode_offsets);
|
||||
exprlist.add(assign);
|
||||
break;
|
||||
case opc_iastore:
|
||||
@ -414,7 +368,8 @@ public class ExprProcessor implements CodeConstants {
|
||||
Exprent index_store = stack.pop();
|
||||
Exprent arr_store = stack.pop();
|
||||
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);
|
||||
break;
|
||||
case opc_iadd:
|
||||
@ -437,7 +392,7 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_lrem:
|
||||
case opc_frem:
|
||||
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;
|
||||
case opc_ishl:
|
||||
case opc_lshl:
|
||||
@ -451,19 +406,20 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_lor:
|
||||
case opc_ixor:
|
||||
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;
|
||||
case opc_ineg:
|
||||
case opc_lneg:
|
||||
case opc_fneg:
|
||||
case opc_dneg:
|
||||
pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack));
|
||||
pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack, bytecode_offsets));
|
||||
break;
|
||||
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(
|
||||
instr.getOperand(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))))}))));
|
||||
instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD, Arrays
|
||||
.asList(vevar.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null)),
|
||||
bytecode_offsets), bytecode_offsets));
|
||||
break;
|
||||
case opc_i2l:
|
||||
case opc_i2f:
|
||||
@ -480,14 +436,14 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_i2b:
|
||||
case opc_i2c:
|
||||
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;
|
||||
case opc_lcmp:
|
||||
case opc_fcmpl:
|
||||
case opc_fcmpg:
|
||||
case opc_dcmpl:
|
||||
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;
|
||||
case opc_ifeq:
|
||||
case opc_ifne:
|
||||
@ -495,7 +451,7 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_ifge:
|
||||
case opc_ifgt:
|
||||
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;
|
||||
case opc_if_icmpeq:
|
||||
case opc_if_icmpne:
|
||||
@ -505,15 +461,15 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_if_icmple:
|
||||
case opc_if_acmpeq:
|
||||
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;
|
||||
case opc_ifnull:
|
||||
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;
|
||||
case opc_tableswitch:
|
||||
case opc_lookupswitch:
|
||||
exprlist.add(new SwitchExprent(stack.pop()));
|
||||
exprlist.add(new SwitchExprent(stack.pop(), bytecode_offsets));
|
||||
break;
|
||||
case opc_ireturn:
|
||||
case opc_lreturn:
|
||||
@ -524,51 +480,47 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_athrow:
|
||||
exprlist.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
|
||||
instr.opcode == opc_return ? null : stack.pop(),
|
||||
instr.opcode == opc_athrow
|
||||
? null
|
||||
: ((MethodDescriptor)DecompilerContext
|
||||
.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret));
|
||||
instr.opcode == opc_athrow ? null : methodDescriptor.ret,
|
||||
bytecode_offsets));
|
||||
break;
|
||||
case opc_monitorenter:
|
||||
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;
|
||||
case opc_checkcast:
|
||||
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:
|
||||
pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode).intValue(), stack));
|
||||
pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode), stack, bytecode_offsets));
|
||||
break;
|
||||
case opc_getstatic:
|
||||
case opc_getfield:
|
||||
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;
|
||||
case opc_putstatic:
|
||||
case opc_putfield:
|
||||
Exprent valfield = stack.pop();
|
||||
Exprent exprfield =
|
||||
new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_putstatic ? null : stack.pop());
|
||||
exprlist.add(new AssignmentExprent(exprfield, valfield));
|
||||
new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == opc_putstatic ? null : stack.pop(),
|
||||
bytecode_offsets);
|
||||
exprlist.add(new AssignmentExprent(exprfield, valfield, bytecode_offsets));
|
||||
break;
|
||||
case opc_invokevirtual:
|
||||
case opc_invokespecial:
|
||||
case opc_invokestatic:
|
||||
case opc_invokeinterface:
|
||||
case opc_invokedynamic:
|
||||
if (instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
|
||||
|
||||
LinkConstant invoke_constant = pool.getLinkConstant(instr.getOperand(0));
|
||||
int dynamic_invokation_type = -1;
|
||||
if (instr.opcode != opc_invokedynamic || instr.bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) {
|
||||
LinkConstant invoke_constant = pool.getLinkConstant(instr.operand(0));
|
||||
|
||||
List<PooledConstant> bootstrap_arguments = null;
|
||||
if (instr.opcode == opc_invokedynamic && bootstrap != null) {
|
||||
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
|
||||
LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
|
||||
|
||||
dynamic_invokation_type = content_method_handle.index1;
|
||||
bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.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) {
|
||||
exprlist.add(exprinv);
|
||||
}
|
||||
@ -580,15 +532,15 @@ public class ExprProcessor implements CodeConstants {
|
||||
case opc_new:
|
||||
case opc_anewarray:
|
||||
case opc_multianewarray:
|
||||
int arrdims = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.getOperand(1);
|
||||
VarType arrtype = new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true);
|
||||
int dimensions = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.operand(1);
|
||||
VarType arrType = new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true);
|
||||
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;
|
||||
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;
|
||||
case opc_dup:
|
||||
pushEx(stack, exprlist, stack.getByOffset(-1).copy());
|
||||
@ -597,7 +549,7 @@ public class ExprProcessor implements CodeConstants {
|
||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||
break;
|
||||
case opc_dup_x2:
|
||||
if (stack.getByOffset(-2).getExprType().stack_size == 2) {
|
||||
if (stack.getByOffset(-2).getExprType().stackSize == 2) {
|
||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||
}
|
||||
else {
|
||||
@ -605,7 +557,7 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
break;
|
||||
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());
|
||||
}
|
||||
else {
|
||||
@ -614,7 +566,7 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
break;
|
||||
case opc_dup2_x1:
|
||||
if (stack.getByOffset(-1).getExprType().stack_size == 2) {
|
||||
if (stack.getByOffset(-1).getExprType().stackSize == 2) {
|
||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||
}
|
||||
else {
|
||||
@ -623,8 +575,8 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
break;
|
||||
case opc_dup2_x2:
|
||||
if (stack.getByOffset(-1).getExprType().stack_size == 2) {
|
||||
if (stack.getByOffset(-2).getExprType().stack_size == 2) {
|
||||
if (stack.getByOffset(-1).getExprType().stackSize == 2) {
|
||||
if (stack.getByOffset(-2).getExprType().stackSize == 2) {
|
||||
insertByOffsetEx(-2, stack, exprlist, -1);
|
||||
}
|
||||
else {
|
||||
@ -632,7 +584,7 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
}
|
||||
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, -1);
|
||||
}
|
||||
@ -647,12 +599,38 @@ public class ExprProcessor implements CodeConstants {
|
||||
stack.pop();
|
||||
break;
|
||||
case opc_pop:
|
||||
case opc_pop2:
|
||||
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) {
|
||||
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);
|
||||
var.setStack(true);
|
||||
|
||||
exprlist.add(new AssignmentExprent(var, exprent));
|
||||
exprlist.add(new AssignmentExprent(var, exprent, null));
|
||||
stack.push(var.copy());
|
||||
}
|
||||
|
||||
@ -670,20 +648,20 @@ public class ExprProcessor implements CodeConstants {
|
||||
|
||||
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--) {
|
||||
Exprent varex = stack.pop();
|
||||
VarExprent varnew = new VarExprent(base + i + 1, varex.getExprType(), varProcessor);
|
||||
varnew.setStack(true);
|
||||
exprlist.add(new AssignmentExprent(varnew, varex));
|
||||
exprlist.add(new AssignmentExprent(varnew, varex, null));
|
||||
lst.add(0, (VarExprent)varnew.copy());
|
||||
}
|
||||
|
||||
Exprent exprent = lst.get(lst.size() + copyoffset).copy();
|
||||
VarExprent var = new VarExprent(base + offset, exprent.getExprType(), varProcessor);
|
||||
var.setStack(true);
|
||||
exprlist.add(new AssignmentExprent(var, exprent));
|
||||
exprlist.add(new AssignmentExprent(var, exprent, null));
|
||||
lst.add(0, (VarExprent)var.copy());
|
||||
|
||||
for (VarExprent expr : lst) {
|
||||
@ -696,7 +674,6 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
|
||||
public static String getTypeName(VarType type, boolean getShort) {
|
||||
|
||||
int tp = type.type;
|
||||
if (tp <= CodeConstants.TYPE_BOOLEAN) {
|
||||
return typeNames[tp];
|
||||
@ -731,12 +708,9 @@ public class ExprProcessor implements CodeConstants {
|
||||
}
|
||||
|
||||
public static String getCastTypeName(VarType type, boolean getShort) {
|
||||
String s = getTypeName(type, getShort);
|
||||
int dim = type.arraydim;
|
||||
while (dim-- > 0) {
|
||||
s += "[]";
|
||||
}
|
||||
return s;
|
||||
StringBuilder s = new StringBuilder(getTypeName(type, getShort));
|
||||
TextUtil.append(s, "[]", type.arrayDim);
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
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());
|
||||
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());
|
||||
return prlst;
|
||||
}
|
||||
|
||||
public static boolean endsWithSemikolon(Exprent expr) {
|
||||
public static boolean endsWithSemicolon(Exprent expr) {
|
||||
int type = expr.type;
|
||||
return !(type == Exprent.EXPRENT_SWITCH ||
|
||||
type == Exprent.EXPRENT_MONITOR ||
|
||||
type == Exprent.EXPRENT_IF ||
|
||||
(type == Exprent.EXPRENT_VAR && ((VarExprent)expr)
|
||||
.isClassdef()));
|
||||
(type == Exprent.EXPRENT_VAR && ((VarExprent)expr).isClassDef()));
|
||||
}
|
||||
|
||||
public static String jmpWrapper(Statement stat, int indent, boolean semicolon, BytecodeMappingTracer tracer) {
|
||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||
private static void addDeletedGotoInstructionMapping(Statement stat, BytecodeMappingTracer tracer) {
|
||||
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();
|
||||
String content = 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);
|
||||
}
|
||||
public static TextBuffer jmpWrapper(Statement stat, int indent, boolean semicolon, BytecodeMappingTracer tracer) {
|
||||
TextBuffer buf = stat.toJava(indent, tracer);
|
||||
|
||||
List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
|
||||
if (lstSuccs.size() == 1) {
|
||||
StatEdge edge = lstSuccs.get(0);
|
||||
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()) {
|
||||
case StatEdge.TYPE_BREAK:
|
||||
addDeletedGotoInstructionMapping(stat, tracer);
|
||||
buf.append("break");
|
||||
break;
|
||||
case StatEdge.TYPE_CONTINUE:
|
||||
addDeletedGotoInstructionMapping(stat, tracer);
|
||||
buf.append("continue");
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (buf.length() == 0 && semicolon) {
|
||||
buf.append(InterpreterUtil.getIndentString(indent)).append(";").append(new_line_separator);
|
||||
buf.appendIndent(indent).append(";").appendLineSeparator();
|
||||
tracer.incrementCurrentSourceLine();
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static String buildJavaClassName(String name) {
|
||||
@ -815,92 +791,59 @@ public class ExprProcessor implements CodeConstants {
|
||||
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()) {
|
||||
return "";
|
||||
return new TextBuffer();
|
||||
}
|
||||
|
||||
String indstr = InterpreterUtil.getIndentString(indent);
|
||||
String new_line_separator = DecompilerContext.getNewLineSeparator();
|
||||
TextBuffer buf = new TextBuffer();
|
||||
|
||||
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 (expr instanceof VarExprent || expr instanceof AssignmentExprent) {
|
||||
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);
|
||||
if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent)expr).isClassDef()) {
|
||||
buf.appendIndent(indent);
|
||||
}
|
||||
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
|
||||
}
|
||||
if (endsWithSemikolon(expr)) {
|
||||
if (endsWithSemicolon(expr)) {
|
||||
buf.append(";");
|
||||
}
|
||||
buf.append(new_line_separator);
|
||||
|
||||
buf.appendLineSeparator();
|
||||
tracer.incrementCurrentSourceLine();
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static ConstExprent getDefaultArrayValue(VarType arrtype) {
|
||||
|
||||
ConstExprent defaultval;
|
||||
if (arrtype.type == CodeConstants.TYPE_OBJECT || arrtype.arraydim > 0) {
|
||||
defaultval = new ConstExprent(VarType.VARTYPE_NULL, null);
|
||||
public static ConstExprent getDefaultArrayValue(VarType arrType) {
|
||||
ConstExprent defaultVal;
|
||||
if (arrType.type == CodeConstants.TYPE_OBJECT || arrType.arrayDim > 0) {
|
||||
defaultVal = new ConstExprent(VarType.VARTYPE_NULL, null, null);
|
||||
}
|
||||
else if (arrtype.type == CodeConstants.TYPE_FLOAT) {
|
||||
defaultval = new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
|
||||
else if (arrType.type == CodeConstants.TYPE_FLOAT) {
|
||||
defaultVal = new ConstExprent(VarType.VARTYPE_FLOAT, 0f, null);
|
||||
}
|
||||
else if (arrtype.type == CodeConstants.TYPE_LONG) {
|
||||
defaultval = new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
|
||||
else if (arrType.type == CodeConstants.TYPE_LONG) {
|
||||
defaultVal = new ConstExprent(VarType.VARTYPE_LONG, 0L, null);
|
||||
}
|
||||
else if (arrtype.type == CodeConstants.TYPE_DOUBLE) {
|
||||
defaultval = new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
|
||||
else if (arrType.type == CodeConstants.TYPE_DOUBLE) {
|
||||
defaultVal = new ConstExprent(VarType.VARTYPE_DOUBLE, 0d, null);
|
||||
}
|
||||
else { // integer types
|
||||
defaultval = new ConstExprent(0, true);
|
||||
defaultVal = new ConstExprent(0, true, null);
|
||||
}
|
||||
|
||||
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);
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
public static boolean getCastedExprent(Exprent exprent,
|
||||
@ -908,44 +851,89 @@ public class ExprProcessor implements CodeConstants {
|
||||
TextBuffer buffer,
|
||||
int indent,
|
||||
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();
|
||||
|
||||
String res = exprent.toJava(indent, tracer);
|
||||
|
||||
boolean cast =
|
||||
!leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT);
|
||||
cast |= castAlways && !leftType.equals(rightType); // Spigot
|
||||
castAlways ||
|
||||
(!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) {
|
||||
// check for a nameless anonymous class
|
||||
cast = !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType));
|
||||
}
|
||||
if (!cast) {
|
||||
cast = isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType);
|
||||
}
|
||||
boolean quote = cast && exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST);
|
||||
|
||||
if (cast) {
|
||||
if (exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
|
||||
res = "(" + res + ")";
|
||||
// cast instead to 'byte' / 'short' when int constant is used as a value for 'Byte' / 'Short'
|
||||
if (castNarrowing && exprent.type == Exprent.EXPRENT_CONST && !((ConstExprent) exprent).isNull()) {
|
||||
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) {
|
||||
|
||||
if (exprent.type == Exprent.EXPRENT_CONST) {
|
||||
ConstExprent cexpr = (ConstExprent)exprent;
|
||||
switch (cexpr.getConsttype().type) {
|
||||
switch (((ConstExprent)exprent).getConstType().type) {
|
||||
case CodeConstants.TYPE_BYTE:
|
||||
case CodeConstants.TYPE_BYTECHAR:
|
||||
case CodeConstants.TYPE_SHORT:
|
||||
@ -957,4 +945,9 @@ public class ExprProcessor implements CodeConstants {
|
||||
|
||||
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-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.
|
||||
*/
|
||||
// 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.modules.decompiler;
|
||||
|
||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
|
||||
@ -28,17 +14,13 @@ public class ExprentStack extends ListStack<Exprent> {
|
||||
pointer = list.getPointer();
|
||||
}
|
||||
|
||||
public Exprent push(Exprent item) {
|
||||
super.push(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exprent pop() {
|
||||
|
||||
return this.remove(--pointer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExprentStack clone() {
|
||||
return new ExprentStack(this);
|
||||
}
|
||||
|
@ -1,21 +1,10 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
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.ControlFlowGraph;
|
||||
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.Statement;
|
||||
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.gen.MethodDescriptor;
|
||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
|
||||
@ -45,30 +36,24 @@ import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
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 Map<Integer, Integer> catchallBlockIDs = new HashMap<Integer, Integer>();
|
||||
private final MethodDescriptor methodDescriptor;
|
||||
private final VarProcessor varProcessor;
|
||||
|
||||
private VarProcessor varprocessor;
|
||||
|
||||
public FinallyProcessor(VarProcessor varprocessor) {
|
||||
this.varprocessor = varprocessor;
|
||||
public FinallyProcessor(MethodDescriptor md, VarProcessor varProc) {
|
||||
methodDescriptor = md;
|
||||
varProcessor = varProc;
|
||||
}
|
||||
|
||||
public boolean iterateGraph(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
|
||||
// return processStatement(mt, root, graph, root);
|
||||
return processStatementEx(mt, root, graph);
|
||||
}
|
||||
public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, ControlFlowGraph graph) {
|
||||
int bytecodeVersion = mt.getBytecodeVersion();
|
||||
|
||||
private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
|
||||
|
||||
int bytecode_version = mt.getClassStruct().getBytecodeVersion();
|
||||
|
||||
LinkedList<Statement> stack = new LinkedList<Statement>();
|
||||
LinkedList<Statement> stack = new LinkedList<>();
|
||||
stack.add(root);
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
|
||||
Statement stat = stack.removeLast();
|
||||
|
||||
Statement parent = stat.getParent();
|
||||
@ -83,30 +68,26 @@ public class FinallyProcessor {
|
||||
// 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));
|
||||
fin.setMonitor(var == null ? null : new VarExprent(var, VarType.VARTYPE_INT, varProcessor));
|
||||
}
|
||||
else {
|
||||
|
||||
Record inf = getFinallyInformation(mt, root, fin);
|
||||
Record inf = getFinallyInformation(cl, 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, bytecodeVersion);
|
||||
|
||||
int varindex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
|
||||
insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
|
||||
|
||||
finallyBlockIDs.put(handler.id, varindex);
|
||||
finallyBlockIDs.put(handler.id, varIndex);
|
||||
}
|
||||
|
||||
DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
|
||||
@ -124,63 +105,7 @@ public class FinallyProcessor {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 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 static final class Record {
|
||||
private final int firstCode;
|
||||
private final Map<BasicBlock, Boolean> mapLast;
|
||||
|
||||
@ -190,10 +115,8 @@ public class FinallyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Record getFinallyInformation(StructMethod mt, RootStatement root, CatchAllStatement fstat) {
|
||||
|
||||
Map<BasicBlock, Boolean> mapLast = new HashMap<BasicBlock, Boolean>();
|
||||
private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) {
|
||||
Map<BasicBlock, Boolean> mapLast = new HashMap<>();
|
||||
|
||||
BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
|
||||
BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
|
||||
@ -209,26 +132,25 @@ public class FinallyProcessor {
|
||||
firstcode = 2;
|
||||
}
|
||||
|
||||
ExprProcessor proc = new ExprProcessor();
|
||||
proc.processStatement(root, mt.getClassStruct());
|
||||
ExprProcessor proc = new ExprProcessor(methodDescriptor, varProcessor);
|
||||
proc.processStatement(root, cl);
|
||||
|
||||
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
|
||||
ssa.splitVariables(root, mt);
|
||||
|
||||
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();
|
||||
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
||||
|
||||
LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
|
||||
LinkedList<DirectNode> stack = new LinkedList<>();
|
||||
stack.add(dgraph.first);
|
||||
|
||||
Set<DirectNode> setVisited = new HashSet<DirectNode>();
|
||||
Set<DirectNode> setVisited = new HashSet<>();
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
|
||||
DirectNode node = stack.removeFirst();
|
||||
|
||||
if (setVisited.contains(node)) {
|
||||
@ -259,7 +181,7 @@ public class FinallyProcessor {
|
||||
|
||||
boolean found = false;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@ -269,7 +191,7 @@ public class FinallyProcessor {
|
||||
found = false;
|
||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -287,7 +209,7 @@ public class FinallyProcessor {
|
||||
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||
AssignmentExprent assexpr = (AssignmentExprent)exprent;
|
||||
if (assexpr.getRight().type == Exprent.EXPRENT_VAR &&
|
||||
new VarVersionPaar((VarExprent)assexpr.getRight()).equals(varpaar)) {
|
||||
new VarVersionPair((VarExprent)assexpr.getRight()).equals(varpaar)) {
|
||||
|
||||
Exprent next = null;
|
||||
if (i == node.exprents.size() - 1) {
|
||||
@ -305,7 +227,7 @@ public class FinallyProcessor {
|
||||
boolean found = false;
|
||||
if (next != null && next.type == Exprent.EXPRENT_EXIT) {
|
||||
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())) {
|
||||
found = true;
|
||||
}
|
||||
@ -375,8 +297,7 @@ public class FinallyProcessor {
|
||||
int var,
|
||||
Record information,
|
||||
int bytecode_version) {
|
||||
|
||||
Set<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry);
|
||||
Set<BasicBlock> setCopy = new HashSet<>(setTry);
|
||||
|
||||
int finallytype = information.firstCode;
|
||||
Map<BasicBlock, Boolean> mapLast = information.mapLast;
|
||||
@ -394,21 +315,15 @@ public class FinallyProcessor {
|
||||
|
||||
// disable semaphore at statement exit points
|
||||
for (BasicBlock block : setTry) {
|
||||
|
||||
List<BasicBlock> lstSucc = block.getSuccs();
|
||||
for (BasicBlock dest : lstSucc) {
|
||||
|
||||
for (BasicBlock dest : lstSucc) {
|
||||
// break out
|
||||
if (!setCopy.contains(dest) && dest != graph.getLast()) {
|
||||
if (dest != graph.getLast() && !setCopy.contains(dest)) {
|
||||
// disable semaphore
|
||||
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||
|
||||
seq.addInstruction(ConstantsUtil
|
||||
.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version,
|
||||
new int[]{0}), -1);
|
||||
seq.addInstruction(ConstantsUtil
|
||||
.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version,
|
||||
new int[]{var}), -1);
|
||||
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1);
|
||||
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}), -1);
|
||||
|
||||
// build a separate block
|
||||
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();
|
||||
seq.addInstruction(
|
||||
ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}),
|
||||
-1);
|
||||
seq.addInstruction(
|
||||
ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}),
|
||||
-1);
|
||||
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}), -1);
|
||||
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}), -1);
|
||||
|
||||
BasicBlock newhead = new BasicBlock(++graph.last_id);
|
||||
newhead.setSeq(seq);
|
||||
@ -451,12 +362,8 @@ public class FinallyProcessor {
|
||||
|
||||
// initialize semaphor with false
|
||||
seq = new SimpleInstructionSequence();
|
||||
seq.addInstruction(
|
||||
ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}),
|
||||
-1);
|
||||
seq.addInstruction(
|
||||
ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}),
|
||||
-1);
|
||||
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1);
|
||||
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}), -1);
|
||||
|
||||
BasicBlock newheadinit = new BasicBlock(++graph.last_id);
|
||||
newheadinit.setSeq(seq);
|
||||
@ -466,7 +373,7 @@ public class FinallyProcessor {
|
||||
setCopy.add(newhead);
|
||||
setCopy.add(newheadinit);
|
||||
|
||||
for (BasicBlock hd : new HashSet<BasicBlock>(newheadinit.getSuccExceptions())) {
|
||||
for (BasicBlock hd : new HashSet<>(newheadinit.getSuccExceptions())) {
|
||||
ExceptionRangeCFG range = graph.getExceptionRange(hd, newheadinit);
|
||||
|
||||
if (setCopy.containsAll(range.getProtectedRange())) {
|
||||
@ -476,10 +383,8 @@ public class FinallyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) {
|
||||
|
||||
List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
|
||||
List<BasicBlock> lstTemp = new ArrayList<>();
|
||||
lstTemp.addAll(oldblock.getPreds());
|
||||
lstTemp.addAll(oldblock.getPredExceptions());
|
||||
|
||||
@ -510,9 +415,8 @@ public class FinallyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static HashSet<BasicBlock> getAllBasicBlocks(Statement stat) {
|
||||
|
||||
List<Statement> lst = new LinkedList<Statement>();
|
||||
private static Set<BasicBlock> getAllBasicBlocks(Statement stat) {
|
||||
List<Statement> lst = new LinkedList<>();
|
||||
lst.add(stat);
|
||||
|
||||
int index = 0;
|
||||
@ -529,7 +433,7 @@ public class FinallyProcessor {
|
||||
}
|
||||
while (index < lst.size());
|
||||
|
||||
HashSet<BasicBlock> res = new LinkedHashSet<BasicBlock>(); // Spigot: Fix determinism
|
||||
Set<BasicBlock> res = new HashSet<>();
|
||||
|
||||
for (Statement st : lst) {
|
||||
res.add(((BasicBlockStatement)st).getBlock());
|
||||
@ -538,11 +442,9 @@ public class FinallyProcessor {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Record information) {
|
||||
|
||||
HashSet<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
|
||||
HashSet<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
|
||||
Set<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
|
||||
Set<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
|
||||
|
||||
int finallytype = information.firstCode;
|
||||
Map<BasicBlock, Boolean> mapLast = information.mapLast;
|
||||
@ -571,7 +473,7 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
// identify start blocks
|
||||
HashSet<BasicBlock> startBlocks = new LinkedHashSet<BasicBlock>(); // Spigot: Fix determinism
|
||||
Set<BasicBlock> startBlocks = new HashSet<>();
|
||||
for (BasicBlock block : tryBlocks) {
|
||||
startBlocks.addAll(block.getSuccs());
|
||||
}
|
||||
@ -580,7 +482,7 @@ public class FinallyProcessor {
|
||||
startBlocks.remove(graph.getLast());
|
||||
startBlocks.removeAll(tryBlocks);
|
||||
|
||||
List<Area> lstAreas = new ArrayList<Area>();
|
||||
List<Area> lstAreas = new ArrayList<>();
|
||||
|
||||
for (BasicBlock start : startBlocks) {
|
||||
|
||||
@ -620,7 +522,7 @@ public class FinallyProcessor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class Area {
|
||||
private static final class Area {
|
||||
private final BasicBlock start;
|
||||
private final Set<BasicBlock> sample;
|
||||
private final BasicBlock next;
|
||||
@ -634,33 +536,32 @@ public class FinallyProcessor {
|
||||
|
||||
private Area compareSubgraphsEx(ControlFlowGraph graph,
|
||||
BasicBlock startSample,
|
||||
HashSet<BasicBlock> catchBlocks,
|
||||
Set<BasicBlock> catchBlocks,
|
||||
BasicBlock startCatch,
|
||||
int finallytype,
|
||||
Map<BasicBlock, Boolean> mapLast,
|
||||
boolean skippedFirst) {
|
||||
|
||||
class BlockStackEntry {
|
||||
public BasicBlock blockCatch;
|
||||
public BasicBlock blockSample;
|
||||
public final BasicBlock blockCatch;
|
||||
public final BasicBlock blockSample;
|
||||
|
||||
// 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.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()) {
|
||||
|
||||
@ -693,7 +594,6 @@ public class FinallyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// exception successors
|
||||
if (isLastBlock && blockSample.getSeq().isEmpty()) {
|
||||
// do nothing, blockSample will be removed anyway
|
||||
@ -721,8 +621,8 @@ public class FinallyProcessor {
|
||||
|
||||
if (instrCatch.opcode == CodeConstants.opc_astore &&
|
||||
instrSample.opcode == CodeConstants.opc_astore) {
|
||||
lst = new ArrayList<int[]>(lst);
|
||||
lst.add(new int[]{instrCatch.getOperand(0), instrSample.getOperand(0)});
|
||||
lst = new ArrayList<>(lst);
|
||||
lst.add(new int[]{instrCatch.operand(0), instrSample.operand(0)});
|
||||
}
|
||||
}
|
||||
|
||||
@ -740,7 +640,7 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
if (isLastBlock) {
|
||||
Set<BasicBlock> setSuccs = new HashSet<BasicBlock>(blockSample.getSuccs());
|
||||
Set<BasicBlock> setSuccs = new HashSet<>(blockSample.getSuccs());
|
||||
setSuccs.removeAll(setSample);
|
||||
|
||||
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) {
|
||||
|
||||
// precondition: there is at most one true exit path in a finally statement
|
||||
|
||||
BasicBlock next = null;
|
||||
@ -800,13 +699,11 @@ public class FinallyProcessor {
|
||||
Instruction instrNext = seqNext.getInstr(i);
|
||||
Instruction instrBlock = seqBlock.getInstr(i);
|
||||
|
||||
if (instrNext.opcode != instrBlock.opcode || instrNext.wide != instrBlock.wide
|
||||
|| instrNext.operandsCount() != instrBlock.operandsCount()) {
|
||||
if (!Instruction.equals(instrNext, instrBlock)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int j = 0; j < instrNext.getOperands().length; j++) {
|
||||
if (instrNext.getOperand(j) != instrBlock.getOperand(j)) {
|
||||
for (int j = 0; j < instrNext.operandsCount(); j++) {
|
||||
if (instrNext.operand(j) != instrBlock.operand(j)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -848,7 +745,6 @@ public class FinallyProcessor {
|
||||
int type,
|
||||
int finallytype,
|
||||
List<int[]> lstStoreVars) {
|
||||
|
||||
InstructionSequence seqPattern = pattern.getSeq();
|
||||
InstructionSequence seqSample = sample.getSeq();
|
||||
|
||||
@ -863,11 +759,11 @@ public class FinallyProcessor {
|
||||
|
||||
if ((type & 2) > 0) { // last
|
||||
if (finallytype == 0 || finallytype == 2) {
|
||||
seqPattern.removeInstruction(seqPattern.length() - 1);
|
||||
seqPattern.removeLast();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||
LinkedList<Integer> oldOffsets = new LinkedList<>();
|
||||
for (int i = seqSample.length() - 1; i >= seqPattern.length(); i--) {
|
||||
seq.addInstruction(0, seqSample.getInstr(i), -1);
|
||||
oldOffsets.addFirst(sample.getOldOffset(i));
|
||||
seqSample.removeInstruction(i);
|
||||
}
|
||||
|
||||
BasicBlock newblock = new BasicBlock(++graph.last_id);
|
||||
newblock.setSeq(seq);
|
||||
newblock.getInstrOldOffsets().addAll(oldOffsets);
|
||||
|
||||
List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
|
||||
lstTemp.addAll(sample.getSuccs());
|
||||
List<BasicBlock> lstTemp = new ArrayList<>(sample.getSuccs());
|
||||
|
||||
// move successors
|
||||
for (BasicBlock suc : lstTemp) {
|
||||
@ -930,19 +827,15 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
public boolean equalInstructions(Instruction first, Instruction second, List<int[]> lstStoreVars) {
|
||||
if (first.opcode != second.opcode || first.wide != second.wide
|
||||
|| first.operandsCount() != second.operandsCount()) {
|
||||
if (!Instruction.equals(first, second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (first.group != CodeConstants.GROUP_JUMP && first.getOperands() != null) { // FIXME: switch comparison
|
||||
for (int i = 0; i < first.getOperands().length; i++) {
|
||||
|
||||
int firstOp = first.getOperand(i);
|
||||
int secondOp = second.getOperand(i);
|
||||
|
||||
if (first.group != CodeConstants.GROUP_JUMP) { // FIXME: switch comparison
|
||||
for (int i = 0; i < first.operandsCount(); i++) {
|
||||
int firstOp = first.operand(i);
|
||||
int secondOp = second.operand(i);
|
||||
if (firstOp != secondOp) {
|
||||
|
||||
// a-load/store instructions
|
||||
if (first.opcode == CodeConstants.opc_aload || first.opcode == CodeConstants.opc_astore) {
|
||||
for (int[] arr : lstStoreVars) {
|
||||
@ -961,7 +854,6 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
private static void deleteArea(ControlFlowGraph graph, Area area) {
|
||||
|
||||
BasicBlock start = area.start;
|
||||
BasicBlock next = area.next;
|
||||
|
||||
@ -975,14 +867,14 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
|
||||
}
|
||||
|
||||
boolean is_outside_range = false;
|
||||
|
||||
Set<BasicBlock> setPredecessors = new HashSet<BasicBlock>(start.getPreds());
|
||||
Set<BasicBlock> setPredecessors = new HashSet<>(start.getPreds());
|
||||
|
||||
// replace start with next
|
||||
for (BasicBlock pred : setPredecessors) {
|
||||
@ -1004,7 +896,7 @@ public class FinallyProcessor {
|
||||
is_outside_range = true;
|
||||
}
|
||||
|
||||
Set<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
|
||||
Set<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<>();
|
||||
for (BasicBlock handler : block.getSuccExceptions()) {
|
||||
setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
|
||||
}
|
||||
@ -1019,7 +911,7 @@ public class FinallyProcessor {
|
||||
// shift extern edges on splitted blocks
|
||||
if (block.getSeq().isEmpty() && block.getSuccs().size() == 1) {
|
||||
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)) {
|
||||
pred.replaceSuccessor(block, succs);
|
||||
}
|
||||
@ -1035,18 +927,15 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
if (is_outside_range) {
|
||||
|
||||
// new empty block
|
||||
BasicBlock emptyblock = new BasicBlock(++graph.last_id);
|
||||
emptyblock.setSeq(new SimpleInstructionSequence());
|
||||
|
||||
graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
|
||||
|
||||
// add to ranges if necessary
|
||||
if (setCommonRemovedExceptionRanges != null) {
|
||||
for (ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
|
||||
emptyblock.addSuccessorException(range.getHandler());
|
||||
range.getProtectedRange().add(emptyblock);
|
||||
}
|
||||
for (ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
|
||||
emptyblock.addSuccessorException(range.getHandler());
|
||||
range.getProtectedRange().add(emptyblock);
|
||||
}
|
||||
|
||||
// insert between predecessors and next
|
||||
@ -1058,7 +947,6 @@ public class FinallyProcessor {
|
||||
}
|
||||
|
||||
private static void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) {
|
||||
|
||||
InstructionSequence seq = block.getSeq();
|
||||
|
||||
if (finallytype == 3) { // empty finally handler
|
||||
@ -1075,11 +963,11 @@ public class FinallyProcessor {
|
||||
|
||||
if ((blocktype & 2) > 0) { // last
|
||||
if (finallytype == 2 || finallytype == 0) {
|
||||
seq.removeInstruction(seq.length() - 1);
|
||||
seq.removeLast();
|
||||
}
|
||||
|
||||
if (finallytype == 2) { // astore
|
||||
seq.removeInstruction(seq.length() - 1);
|
||||
seq.removeLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.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.StructGeneralAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class IdeaNotNullHelper {
|
||||
public final class IdeaNotNullHelper {
|
||||
|
||||
|
||||
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)
|
||||
if (ifbranch != null &&
|
||||
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.getExprents().size() == 1 &&
|
||||
ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
|
||||
@ -85,11 +70,10 @@ public class IdeaNotNullHelper {
|
||||
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
||||
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
||||
VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
|
||||
|
||||
// parameter annotations
|
||||
StructAnnotationParameterAttribute param_annotations = (StructAnnotationParameterAttribute)attributes
|
||||
.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
|
||||
StructAnnotationParameterAttribute param_annotations =
|
||||
mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
|
||||
if (param_annotations != null) {
|
||||
|
||||
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);
|
||||
|
||||
for (AnnotationExprent ann : annotations) {
|
||||
if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
|
||||
if (ann.getClassName().equals("org/jetbrains/annotations/NotNull")) {
|
||||
is_notnull_check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,7 +101,7 @@ public class IdeaNotNullHelper {
|
||||
break;
|
||||
}
|
||||
|
||||
index += md.params[i].stack_size;
|
||||
index += md.params[i].stackSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,7 +112,7 @@ public class IdeaNotNullHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeParameterCheck(stat, mt);
|
||||
removeParameterCheck(stat);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -135,7 +120,7 @@ public class IdeaNotNullHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void removeParameterCheck(Statement stat, StructMethod mt) {
|
||||
private static void removeParameterCheck(Statement stat) {
|
||||
|
||||
Statement st = stat.getFirst();
|
||||
while (st.type == Statement.TYPE_SEQUENCE) {
|
||||
@ -144,11 +129,7 @@ public class IdeaNotNullHelper {
|
||||
|
||||
IfStatement ifstat = (IfStatement)st;
|
||||
|
||||
if (ifstat.getElsestat() == null) { // if
|
||||
// TODO:
|
||||
}
|
||||
else { // if - else
|
||||
|
||||
if (ifstat.getElsestat() != null) { // if - else
|
||||
StatEdge ifedge = ifstat.getIfEdge();
|
||||
StatEdge elseedge = ifstat.getElseEdge();
|
||||
|
||||
@ -172,28 +153,22 @@ public class IdeaNotNullHelper {
|
||||
|
||||
private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) {
|
||||
|
||||
VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
|
||||
|
||||
boolean is_notnull_check = false;
|
||||
|
||||
// method annotation, refers to the return value
|
||||
StructAnnotationAttribute attr =
|
||||
(StructAnnotationAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||
StructAnnotationAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||
if (attr != null) {
|
||||
List<AnnotationExprent> annotations = attr.getAnnotations();
|
||||
|
||||
for (AnnotationExprent ann : annotations) {
|
||||
if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
|
||||
if (ann.getClassName().equals("org/jetbrains/annotations/NotNull")) {
|
||||
is_notnull_check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_notnull_check) {
|
||||
return removeReturnCheck(stat, mt);
|
||||
}
|
||||
|
||||
return false;
|
||||
return is_notnull_check && removeReturnCheck(stat, mt);
|
||||
}
|
||||
|
||||
|
||||
@ -205,7 +180,7 @@ public class IdeaNotNullHelper {
|
||||
Exprent exprent = stat.getExprents().get(0);
|
||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||
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();
|
||||
//if(exprent_value.type == Exprent.EXPRENT_VAR) {
|
||||
// VarExprent var_value = (VarExprent)exprent_value;
|
||||
@ -214,7 +189,7 @@ public class IdeaNotNullHelper {
|
||||
Exprent if_condition = ifparent.getHeadexprent().getCondition();
|
||||
|
||||
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;
|
||||
Exprent first_param = func.getLstOperands().get(0);
|
||||
@ -268,7 +243,7 @@ public class IdeaNotNullHelper {
|
||||
Exprent exprent = stat.getExprents().get(0);
|
||||
if (exprent.type == Exprent.EXPRENT_EXIT) {
|
||||
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();
|
||||
|
||||
SequenceStatement sequence = (SequenceStatement)parent;
|
||||
@ -282,7 +257,7 @@ public class IdeaNotNullHelper {
|
||||
Exprent if_condition = ifstat.getHeadexprent().getCondition();
|
||||
|
||||
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;
|
||||
Exprent first_param = func.getLstOperands().get(0);
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.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.Statement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class IfHelper {
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class IfHelper {
|
||||
public static boolean mergeAllIfs(RootStatement root) {
|
||||
|
||||
boolean res = mergeAllIfsRec(root, new HashSet<Integer>());
|
||||
|
||||
boolean res = mergeAllIfsRec(root, new HashSet<>());
|
||||
if (res) {
|
||||
SequenceHelper.condenseSequences(root);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean mergeAllIfsRec(Statement stat, HashSet<Integer> setReorderedIfs) {
|
||||
|
||||
private static boolean mergeAllIfsRec(Statement stat, Set<? super Integer> setReorderedIfs) {
|
||||
boolean res = false;
|
||||
|
||||
if (stat.getExprents() == null) {
|
||||
|
||||
while (true) {
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
for (Statement st : stat.getStats()) {
|
||||
|
||||
res |= mergeAllIfsRec(st, setReorderedIfs);
|
||||
|
||||
// collapse composed if's
|
||||
if (changed = mergeIfs(st, setReorderedIfs)) {
|
||||
if (mergeIfs(st, setReorderedIfs)) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -75,9 +48,7 @@ public class IfHelper {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
public static boolean mergeIfs(Statement statement, HashSet<Integer> setReorderedIfs) {
|
||||
|
||||
public static boolean mergeIfs(Statement statement, Set<? super Integer> setReorderedIfs) {
|
||||
if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
@ -85,10 +56,9 @@ public class IfHelper {
|
||||
boolean res = false;
|
||||
|
||||
while (true) {
|
||||
|
||||
boolean updated = false;
|
||||
|
||||
List<Statement> lst = new ArrayList<Statement>();
|
||||
List<Statement> lst = new ArrayList<>();
|
||||
if (statement.type == Statement.TYPE_IF) {
|
||||
lst.add(statement);
|
||||
}
|
||||
@ -99,7 +69,6 @@ public class IfHelper {
|
||||
boolean stsingle = (lst.size() == 1);
|
||||
|
||||
for (Statement stat : lst) {
|
||||
|
||||
if (stat.type == Statement.TYPE_IF) {
|
||||
IfNode rtnode = buildGraph((IfStatement)stat, stsingle);
|
||||
|
||||
@ -107,22 +76,25 @@ public class IfHelper {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (updated = collapseIfIf(rtnode)) {
|
||||
if (collapseIfIf(rtnode)) {
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!setReorderedIfs.contains(stat.id)) {
|
||||
|
||||
if (updated = collapseIfElse(rtnode)) {
|
||||
if (collapseIfElse(rtnode)) {
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (updated = collapseElse(rtnode)) {
|
||||
if (collapseElse(rtnode)) {
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated = reorderIf((IfStatement)stat)) {
|
||||
if (reorderIf((IfStatement)stat)) {
|
||||
updated = true;
|
||||
setReorderedIfs.add(stat.id);
|
||||
break;
|
||||
}
|
||||
@ -133,14 +105,13 @@ public class IfHelper {
|
||||
break;
|
||||
}
|
||||
|
||||
res |= updated;
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static boolean collapseIfIf(IfNode rtnode) {
|
||||
|
||||
if (rtnode.edgetypes.get(0) == 0) {
|
||||
IfNode ifbranch = rtnode.succs.get(0);
|
||||
if (ifbranch.succs.size() == 2) {
|
||||
@ -158,7 +129,7 @@ public class IfHelper {
|
||||
ifchild.removeSuccessor(ifchild.getAllSuccessorEdges().get(0));
|
||||
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);
|
||||
|
||||
@ -196,11 +167,12 @@ public class IfHelper {
|
||||
// merge if conditions
|
||||
IfExprent statexpr = ifparent.getHeadexprent();
|
||||
|
||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
||||
List<Exprent> lstOperands = new ArrayList<>();
|
||||
lstOperands.add(statexpr.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;
|
||||
}
|
||||
@ -212,11 +184,9 @@ public class IfHelper {
|
||||
}
|
||||
|
||||
private static boolean collapseIfElse(IfNode rtnode) {
|
||||
|
||||
if (rtnode.edgetypes.get(0).intValue() == 0) {
|
||||
if (rtnode.edgetypes.get(0) == 0) {
|
||||
IfNode ifbranch = rtnode.succs.get(0);
|
||||
if (ifbranch.succs.size() == 2) {
|
||||
|
||||
// if-else branch
|
||||
if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
|
||||
|
||||
@ -229,8 +199,8 @@ public class IfHelper {
|
||||
ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
|
||||
ifparent.getStats().removeWithKey(ifchild.id);
|
||||
|
||||
if (ifbranch.edgetypes.get(1).intValue() == 1 &&
|
||||
ifbranch.edgetypes.get(0).intValue() == 1) { // target null
|
||||
if (ifbranch.edgetypes.get(1) == 1 &&
|
||||
ifbranch.edgetypes.get(0) == 1) { // target null
|
||||
|
||||
ifparent.setIfstat(null);
|
||||
|
||||
@ -249,11 +219,11 @@ public class IfHelper {
|
||||
// merge if conditions
|
||||
IfExprent statexpr = ifparent.getHeadexprent();
|
||||
|
||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
||||
List<Exprent> lstOperands = new ArrayList<>();
|
||||
lstOperands.add(statexpr.getCondition());
|
||||
lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
|
||||
Arrays.asList(new Exprent[]{ifchild.getHeadexprent().getCondition()})));
|
||||
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
|
||||
lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, ifchild.getHeadexprent().getCondition(), null));
|
||||
statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands, null));
|
||||
statexpr.addBytecodeOffsets(ifchild.getHeadexprent().bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -264,10 +234,8 @@ public class IfHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static boolean collapseElse(IfNode rtnode) {
|
||||
|
||||
if (rtnode.edgetypes.get(1).intValue() == 0) {
|
||||
if (rtnode.edgetypes.get(1) == 0) {
|
||||
IfNode elsebranch = rtnode.succs.get(1);
|
||||
if (elsebranch.succs.size() == 2) {
|
||||
|
||||
@ -304,18 +272,17 @@ public class IfHelper {
|
||||
// merge if conditions
|
||||
IfExprent statexpr = secondif.getHeadexprent();
|
||||
|
||||
List<Exprent> lstOperands = new ArrayList<Exprent>();
|
||||
List<Exprent> lstOperands = new ArrayList<>();
|
||||
lstOperands.add(firstif.getHeadexprent().getCondition());
|
||||
|
||||
if (path == 2) {
|
||||
lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
|
||||
Arrays.asList(new Exprent[]{lstOperands.get(0)})));
|
||||
lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, lstOperands.get(0), null));
|
||||
}
|
||||
|
||||
lstOperands.add(statexpr.getCondition());
|
||||
|
||||
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() &&
|
||||
!firstif.getFirst().getExprents().isEmpty()) {
|
||||
@ -328,9 +295,7 @@ public class IfHelper {
|
||||
}
|
||||
}
|
||||
else if (elsebranch.succs.size() == 1) {
|
||||
|
||||
if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
|
||||
|
||||
IfStatement firstif = (IfStatement)rtnode.value;
|
||||
Statement second = elsebranch.value;
|
||||
|
||||
@ -359,7 +324,7 @@ public class IfHelper {
|
||||
// negate the if condition
|
||||
IfExprent statexpr = firstif.getHeadexprent();
|
||||
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;
|
||||
}
|
||||
@ -369,9 +334,7 @@ public class IfHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
|
||||
|
||||
if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||
return null;
|
||||
}
|
||||
@ -433,16 +396,14 @@ public class IfHelper {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: rewrite the entire method!!! keep in mind finally exits!!
|
||||
private static boolean reorderIf(IfStatement ifstat) {
|
||||
|
||||
if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ifdirect = false, elsedirect = false;
|
||||
boolean noifstat = false, noelsestat = false;
|
||||
boolean ifdirect, elsedirect;
|
||||
boolean noifstat = false, noelsestat;
|
||||
boolean ifdirectpath = false, elsedirectpath = false;
|
||||
|
||||
Statement parent = ifstat.getParent();
|
||||
@ -453,32 +414,20 @@ public class IfHelper {
|
||||
if (ifstat.getIfstat() == null) {
|
||||
noifstat = true;
|
||||
|
||||
if (ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT) {
|
||||
ifdirect = true;
|
||||
}
|
||||
else {
|
||||
ifdirect = MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
|
||||
}
|
||||
ifdirect = ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT ||
|
||||
MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
|
||||
}
|
||||
else {
|
||||
List<StatEdge> lstSuccs = ifstat.getIfstat().getAllSuccessorEdges();
|
||||
if (!lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
|
||||
ifdirect = true;
|
||||
}
|
||||
else {
|
||||
ifdirect = hasDirectEndEdge(ifstat.getIfstat(), from);
|
||||
}
|
||||
ifdirect = !lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT ||
|
||||
hasDirectEndEdge(ifstat.getIfstat(), from);
|
||||
}
|
||||
|
||||
Statement last = parent.type == Statement.TYPE_SEQUENCE ? parent.getStats().getLast() : ifstat;
|
||||
noelsestat = (last == ifstat);
|
||||
|
||||
if (!last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
|
||||
elsedirect = true;
|
||||
}
|
||||
else {
|
||||
elsedirect = hasDirectEndEdge(last, from);
|
||||
}
|
||||
elsedirect = !last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT ||
|
||||
hasDirectEndEdge(last, from);
|
||||
|
||||
if (!noelsestat && existsPath(ifstat, ifstat.getAllSuccessorEdges().get(0).getDestination())) {
|
||||
return false;
|
||||
@ -496,10 +445,9 @@ public class IfHelper {
|
||||
if (sttemp == ifstat) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (elsedirectpath = existsPath(sttemp, next)) {
|
||||
break;
|
||||
}
|
||||
else if (existsPath(sttemp, next)) {
|
||||
elsedirectpath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -509,7 +457,7 @@ public class IfHelper {
|
||||
SequenceStatement sequence = (SequenceStatement)parent;
|
||||
|
||||
// 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--) {
|
||||
Statement sttemp = sequence.getStats().get(i);
|
||||
if (sttemp == ifstat) {
|
||||
@ -554,7 +502,7 @@ public class IfHelper {
|
||||
|
||||
// negate the if condition
|
||||
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) {
|
||||
StatEdge ifedge = ifstat.getIfEdge();
|
||||
@ -597,7 +545,7 @@ public class IfHelper {
|
||||
SequenceStatement sequence = (SequenceStatement)parent;
|
||||
|
||||
// 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--) {
|
||||
Statement sttemp = sequence.getStats().get(i);
|
||||
if (sttemp == ifstat) {
|
||||
@ -698,9 +646,7 @@ public class IfHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static Statement getNextStatement(Statement stat) {
|
||||
|
||||
Statement parent = stat.getParent();
|
||||
switch (parent.type) {
|
||||
case Statement.TYPE_ROOT:
|
||||
@ -722,7 +668,6 @@ public class IfHelper {
|
||||
}
|
||||
|
||||
private static boolean existsPath(Statement from, Statement to) {
|
||||
|
||||
for (StatEdge edge : to.getAllPredecessorEdges()) {
|
||||
if (from.containsStatementStrict(edge.getSource())) {
|
||||
return true;
|
||||
@ -733,18 +678,17 @@ public class IfHelper {
|
||||
}
|
||||
|
||||
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>();
|
||||
public List<Integer> edgetypes = new ArrayList<Integer>();
|
||||
|
||||
public IfNode(Statement value) {
|
||||
IfNode(Statement value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void addChild(IfNode child, int type) {
|
||||
succs.add(child);
|
||||
edgetypes.add(new Integer(type));
|
||||
edgetypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.modules.decompiler.stats.*;
|
||||
@ -21,7 +7,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class InlineSingleBlockHelper {
|
||||
public final class InlineSingleBlockHelper {
|
||||
|
||||
|
||||
public static boolean inlineSingleBlocks(RootStatement root) {
|
||||
@ -68,7 +54,7 @@ public class InlineSingleBlockHelper {
|
||||
Statement parent = source.getParent();
|
||||
source.removeSuccessor(edge);
|
||||
|
||||
List<Statement> lst = new ArrayList<Statement>();
|
||||
List<Statement> lst = new ArrayList<>();
|
||||
for (int i = seq.getStats().size() - 1; i >= index; i--) {
|
||||
lst.add(0, seq.getStats().remove(i));
|
||||
}
|
||||
@ -132,17 +118,14 @@ public class InlineSingleBlockHelper {
|
||||
StatEdge edge = lst.get(0);
|
||||
|
||||
if (sameCatchRanges(edge)) {
|
||||
if (edge.explicit) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (!edge.explicit) {
|
||||
for (int i = index; i < seq.getStats().size(); i++) {
|
||||
if (!noExitLabels(seq.getStats().get(i), seq)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// FIXME: count labels properly
|
||||
}
|
||||
@ -200,21 +183,13 @@ public class InlineSingleBlockHelper {
|
||||
}
|
||||
|
||||
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 parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH ||
|
||||
isBreakEdgeLabeled(parent, closure);
|
||||
}
|
||||
return parent != closure &&
|
||||
(parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH || isBreakEdgeLabeled(parent, closure));
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.modules.decompiler.exps.Exprent;
|
||||
@ -22,7 +8,7 @@ import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public class LabelHelper {
|
||||
public final class LabelHelper {
|
||||
|
||||
|
||||
public static void cleanUpEdges(RootStatement root) {
|
||||
@ -33,7 +19,7 @@ public class LabelHelper {
|
||||
|
||||
liftClosures(root);
|
||||
|
||||
lowContinueLabels(root, new HashSet<StatEdge>());
|
||||
lowContinueLabels(root, new HashSet<>());
|
||||
|
||||
lowClosures(root);
|
||||
}
|
||||
@ -63,7 +49,7 @@ public class LabelHelper {
|
||||
if (dest.type != Statement.TYPE_DUMMYEXIT) {
|
||||
Statement parent = dest.getParent();
|
||||
|
||||
List<Statement> lst = new ArrayList<Statement>();
|
||||
List<Statement> lst = new ArrayList<>();
|
||||
if (parent.type == Statement.TYPE_SEQUENCE) {
|
||||
lst.addAll(parent.getStats());
|
||||
}
|
||||
@ -131,14 +117,14 @@ public class LabelHelper {
|
||||
lowContinueLabels(st, edges);
|
||||
}
|
||||
else {
|
||||
lowContinueLabels(st, new HashSet<StatEdge>());
|
||||
lowContinueLabels(st, new HashSet<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: ?
|
||||
for (Statement st : stat.getStats()) {
|
||||
@ -181,7 +167,7 @@ public class LabelHelper {
|
||||
|
||||
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) {
|
||||
return mapEdges;
|
||||
@ -279,7 +265,7 @@ public class LabelHelper {
|
||||
Statement stlast = swst.getCaseStatements().get(last);
|
||||
if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
|
||||
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 {
|
||||
mapEdges = setExplicitEdges(stlast);
|
||||
@ -340,7 +326,7 @@ public class LabelHelper {
|
||||
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) {
|
||||
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>();
|
||||
HashSet<Statement> setContinue = new HashSet<Statement>();
|
||||
private static LabelSets processStatementLabel(Statement stat) {
|
||||
LabelSets sets = new LabelSets();
|
||||
|
||||
if (stat.getExprents() == null) {
|
||||
for (Statement st : stat.getStats()) {
|
||||
HashSet<Statement>[] arr = processStatementLabel(st);
|
||||
|
||||
setBreak.addAll(arr[0]);
|
||||
setContinue.addAll(arr[1]);
|
||||
LabelSets nested = processStatementLabel(st);
|
||||
sets.breaks.addAll(nested.breaks);
|
||||
sets.continues.addAll(nested.continues);
|
||||
}
|
||||
|
||||
boolean shieldType = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
|
||||
if (shieldType) {
|
||||
for (StatEdge edge : stat.getLabelEdges()) {
|
||||
if (edge.explicit && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
|
||||
(edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
|
||||
if (edge.explicit && ((edge.getType() == StatEdge.TYPE_BREAK && sets.breaks.contains(edge.getSource())) ||
|
||||
(edge.getType() == StatEdge.TYPE_CONTINUE && sets.continues.contains(edge.getSource())))) {
|
||||
edge.labeled = false;
|
||||
}
|
||||
}
|
||||
@ -445,16 +433,16 @@ public class LabelHelper {
|
||||
|
||||
switch (stat.type) {
|
||||
case Statement.TYPE_DO:
|
||||
setContinue.clear();
|
||||
sets.continues.clear();
|
||||
case Statement.TYPE_SWITCH:
|
||||
setBreak.clear();
|
||||
sets.breaks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
setBreak.add(stat);
|
||||
setContinue.add(stat);
|
||||
sets.breaks.add(stat);
|
||||
sets.continues.add(stat);
|
||||
|
||||
return new HashSet[] { setBreak, setContinue };
|
||||
return sets;
|
||||
}
|
||||
|
||||
public static void replaceContinueWithBreak(Statement stat) {
|
||||
|
@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.modules.decompiler.stats.DoStatement;
|
||||
@ -25,7 +11,7 @@ import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class LoopExtractHelper {
|
||||
public final class LoopExtractHelper {
|
||||
|
||||
|
||||
public static boolean extractLoops(Statement root) {
|
||||
@ -72,9 +58,7 @@ public class LoopExtractHelper {
|
||||
return res ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
private static boolean extractLoop(DoStatement stat) {
|
||||
|
||||
if (stat.getLooptype() != DoStatement.LOOP_DO) {
|
||||
return false;
|
||||
}
|
||||
@ -85,12 +69,7 @@ public class LoopExtractHelper {
|
||||
}
|
||||
}
|
||||
|
||||
if (!extractLastIf(stat)) {
|
||||
return extractFirstIf(stat);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
return extractLastIf(stat) || extractFirstIf(stat);
|
||||
}
|
||||
|
||||
private static boolean extractLastIf(DoStatement stat) {
|
||||
@ -189,7 +168,7 @@ public class LoopExtractHelper {
|
||||
|
||||
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) {
|
||||
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