Java 8 / Fernflower Decompiler: ошибка или особенность - PullRequest
0 голосов
/ 08 марта 2019

OpenJDK 1.8.0_191

Я скомпилировал и декомпилировал фрагмент кода ниже, используя Fernflower.

public class Decompile {
    public static void main(String[] args) {
        final int VAL = 20;
        System.out.println(VAL);
    }
}

Вывод:

public class Decompile {

   public static void main(String[] args) {
      boolean VAL = true;
      System.out.println(20);
   }
}

Я запутался, как VAL стал логическим значением?

UPDATE:

В Intellij IDEA декомпилированный код выглядит так:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

public class Decompile {
    public Decompile() {
    }

    public static void main(String[] args) {
        int VAL = true;
        System.out.println(20);
    }
}

Ответы [ 3 ]

2 голосов
/ 08 марта 2019

Байт-код:

L0
 LINENUMBER 5 L0
 BIPUSH 20
 ISTORE 1
L1
 LINENUMBER 6 L1
 GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
 BIPUSH 20
 INVOKEVIRTUAL java/io/PrintStream.println (I)V

. Как видите, BIPUSH помещает 20 в стек, затем ISTORE принимает значение и сохраняет его в локальной переменной.

Это проблема Fernflower.


Для вашего интереса вывод для версии байт-кода 55 равен

int VAL = true;
System.out.println(20);

Вы видите, что декомпиляторы могут ошибаться:)

1 голос
/ 09 марта 2019

Основная проблема заключается в том, что байт-код Java не имеет никакого представления о логических значениях, байтах, символах или шортах (за исключением сигнатур типов).Все локальные переменные с этими типами вместо этого скомпилированы в int.Логические значения true и false компилируются в 1 и 0 соответственно.

Это означает, что декомпилятор должен угадать, должна ли данная локальная переменная быть логической или целочисленным типом.В этом случае значение 20 сохраняется в переменной, которая никогда не будет храниться в переменной логического типа в коде Java, поэтому декомпилятору должно быть легко угадать, что это целочисленный тип, основанный на контексте,Но похоже, что булев гадатель Fernflower не так уж и искушен.

Для чего бы это ни стоило, это сложная проблема по своей сути.Особенно, если учесть, что байт-код не-Java не должен следовать тем же шаблонам, что и Java.Для байт-кода вполне допустимо использовать одну и ту же переменную как в целочисленном, так и в логическом контекстах. Декомпилятор Кракатау имеет довольно сложный шаг вывода для предположения, должны ли переменные быть логическими, или нет, но в подобных ситуациях все равно будет неправильно.

0 голосов
/ 08 марта 2019

Это работает так, как compiler делает optimization во время генерации byte code.Как VAL = 20;является окончательным и не изменяется, поэтому он может поставить 20 вместо VAL без impacting функциональности во втором выражении.Теперь у decompiler есть только byte code, и когда он начинает читать байт-код, он находит 20 как встроенный в second line.Байт-код, сгенерированный кодом, как показано ниже:

   0: bipush        20
   2: istore_1
   3: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
   6: bipush        20
   8: invokevirtual #26                 // Method java/io/PrintStream.println:(I)V
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...