Как определить тернарный оператор из байт-кода Java

Я работаю над проектом байт-кода Java, и мне нужно определить тернарный оператор и вложенный тернарный оператор.

у меня два вопроса

  1. как определить, что оператор if является тернарным оператором? на основе стека переменные?
  2. как определить потребляемое значение оператора if в опранде стека является результатом тернарного оператора

пример:

((a>b ? 0 : 1 ) > (a > c ? 10 : 20) ? 100 : 101

вот полный пример тройной цепочки операторов:

исходный код:

public void ddddd()
{
    int m,k, n, z;
    Random r = new Random();
    boolean p = (r.nextInt() > 100 || (30 > r.nextInt() ? (r.nextInt() > 4000 ? 1 : 0) : (r.nextInt() > 2000 ? 100 : 20)) <  (r.nextInt() > 1000 ? 0 : 1));
}

структурированный байт-код:

[

   7          astore] java/util/Random var1(1) = <init>(v0)
 [   9           aload] java/util/Random var1(1) = (stack_var)var1
 [  11   invokevirtual] I v11 = var1.nextInt()
 [  14          bipush] (I)v14 = 100
 if { // block_id: 16 16 => 89  parent_id: 0
    [  16       if_icmpgt] v11 > v14 : goto => 85
    if_false_block { // block_id: 15 19 => 89  parent_id: 16
        [  19          bipush] (I)v19 = 30
        [  21           aload] java/util/Random var1(1) = (stack_var)var1
        [  23   invokevirtual] I v23 = var1.nextInt()
        if { // block_id: 9 26 => 64  parent_id: 15
            [  26       if_icmple] v19 <= v23 : goto => 48
            if_false_block { // block_id: 8 29 => 45  parent_id: 9
                [  29           aload] java/util/Random var1(1) = (stack_var)var1
                [  31   invokevirtual] I v31 = var1.nextInt()
                [  34          sipush] (I)v34 = 4000
                if { // block_id: 6 37 => 45  parent_id: 8
                    [  37       if_icmple] v31 <= v34 : goto => 44
                    if_false_block { // block_id: 5 40 => 41  parent_id: 6
                        [  40        iconst_1] (I)v40 = 1
                        [  41            goto] goto: 66
                    }
                    if_true_block { // block_id: 4 44 => 45  parent_id: 6
                        [  44        iconst_0] (I)v44 = 0
                        [  45            goto] goto: 66
                    }
                }
            }
            if_true_block { // block_id: 7 48 => 64  parent_id: 9
                [  48           aload] java/util/Random var1(1) = (stack_var)var1
                [  50   invokevirtual] I v50 = var1.nextInt()
                [  53          sipush] (I)v53 = 2000
                if { // block_id: 3 56 => 64  parent_id: 7
                    [  56       if_icmple] v50 <= v53 : goto => 64
                    if_false_block { // block_id: 2 59 => 61  parent_id: 3
                        [  59          bipush] (I)v59 = 100
                        [  61            goto] goto: 66
                    }
                    if_true_block { // block_id: 1 64 => 64  parent_id: 3
                        [  64          bipush] (I)v64 = 20
                    }
                }
            }
        }
        [  66           aload] java/util/Random var1(1) = (stack_var)var1
        [  68   invokevirtual] I v68 = var1.nextInt()
        [  71          sipush] (I)v71 = 1000
        if { // block_id: 12 74 => 81  parent_id: 15
            [  74       if_icmple] v68 <= v71 : goto => 81
            if_false_block { // block_id: 11 77 => 78  parent_id: 12
                [  77        iconst_0] (I)v77 = 0
                [  78            goto] goto: 82
            }
            if_true_block { // block_id: 10 81 => 81  parent_id: 12
                [  81        iconst_1] (I)v81 = 1
            }
        }
        if { // block_id: 14 82 => 89  parent_id: 15
            [  82       if_icmpge] v40 >= v77 : goto => 89
            [  85        iconst_1] (I)v85 = 1
            [  86            goto] goto: 90
            if_true_block { // block_id: 13 89 => 89  parent_id: 14
                [  89        iconst_0] (I)v89 = 0
            }
        }
    }
 }
 [  90          istore] I var2(1) = (stack_var)var2
 [  92          return] return

Зачем вам это нужно? Байт-код на самом деле не содержит информации о том, как был сгенерирован исходный код. Кроме того, что именно генерирует «структурированный байт-код»?

dan1st 21.04.2024 08:09

Не существует надежного способа сделать это. Тернарный оператор — это особенность языка. Компилятор может скомпилировать его в любую последовательность инструкций, которая ведет себя правильно, что может быть таким же, как то, в которую будет скомпилирован оператор if. И разные компиляторы тоже могут скомпилировать его по-разному. В лучшем случае это похоже на XY-проблему.

Sweeper 21.04.2024 08:11

@dan1st, это декомпилятор, структурированный байт-код, сгенерированный на основе графа потока управления.

Neo 21.04.2024 08:23

@Sweeper, по моему мнению, каждый Java-компилятор компилирует тернарный оператор, как если бы оператор else, тернарный оператор, если else отличается от другого, - это стек операндов, что-то оставляет

Neo 21.04.2024 08:31

Очень актуально: Компилируются ли Ternary и If/Else в одно и то же?

Bohemian 21.04.2024 08:32

@Bohemian, я думаю, это не имеет значения, это действительно зависит от реализации разницы, но есть много тернарных операторов, которые не сохраняются в локальной переменной, просто помещают переменную в стек операндов и используют другие

Neo 21.04.2024 08:40

Так что либо вы сами ответили на свой вопрос, либо ошибаетесь.

user207421 21.04.2024 08:52

и не забывайте, что в новых версиях Java мы также получили выражения переключения...

user85421 21.04.2024 09:08

@user85421 user85421 вы правы, только что протестировали 22 версию, у нее та же проблема с выражениями переключателей, но я думаю, что если проблема с тернарным оператором решена, переключатель тоже решен. кстати, это не проблема XY

Neo 21.04.2024 09:36

@user85421 user85421 большое спасибо за упоминание о проблеме переключения выражений в новых версиях, сэкономьте мое время!

Neo 21.04.2024 10:04
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
10
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой я хочу идентифицировать тернарный оператор, заключается в том, что мне нужно преобразовать байт-код в исходный код. С одним тернарным оператором проще работать, и обычно результат тернарного оператора сохраняется или возвращается, но вложенную цепочку тройных операторов трудно идентифицировать.

Метод, который я основал, не является чем-то вроде SSA FORM. Вместо этого делайте предположения на основе графа потока управления.

Один тернарный оператор идентифицируется в соответствии с графом потока управления. Можно ли сжать тернарный оператор в одну строку, зависит от того, есть ли несжатый тернарный оператор среди дочерних элементов в графе потока управления. Эта рекурсивная обработка может сжать вложенный тернарный оператор в одну строку.

И огромное спасибо user85421 рассказал мне, что в новых версиях Java уже реализован переключатель в качестве оператора множественного возврата в стеке операндов.

Другие вопросы по теме