Декомпиляция java с помощью JAD - ограничения

Я пытаюсь декомпилировать пару файлов jar с помощью JAD на Java (я тоже пробовал JD-GUI, но с еще меньшей удачей), но получаю довольно много ошибок. Один тип (легко исправить), похоже, связан с внутренними классами, но я также нашел этот фрагмент кода:

static int[] $SWITCH_TABLE$atp$com$OrderType()
{
    $SWITCH_TABLE$atp$com$OrderType;
    if($SWITCH_TABLE$atp$com$OrderType == null) goto _L2; else goto _L1
_L1:
    return;
_L2:
    JVM INSTR pop ;
    int ai[] = new int[OrderType.values().length];
    try
    {
        ai[OrderType.LIMIT.ordinal()] = 2;
    }
    catch(NoSuchFieldError _ex) { }
    try
    {
        ai[OrderType.MARKET.ordinal()] = 1;
    }
    catch(NoSuchFieldError _ex) { }
    try
    {
        ai[OrderType.STOP.ordinal()] = 3;
    }
    catch(NoSuchFieldError _ex) { }
    try
    {
        ai[OrderType.TAKE.ordinal()] = 4;
    }
    catch(NoSuchFieldError _ex) { }
    return $SWITCH_TABLE$atp$com$OrderType = ai;
}

который используется следующим образом:

switch($SWITCH_TABLE$atp$com$OrderType()[co.getOrderType().ordinal()])
        {
        case 1: // '\001'
            order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
            break;

        case 2: // '\002'
            order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
            break;

        case 3: // '\003'
            order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
            break;
        }

Есть идеи, чем изначально могла быть эта конструкция?


person Grzenio    schedule 24.10.2011    source источник


Ответы (3)


Я думаю, что это tablewitch для перечисления. Он переводит произвольное порядковое значение enum в число 0..n, что позволяет улучшить производительность оператора switch.

ОБНОВЛЕНИЕ Только понял! Проблема в том, что код, использующий перечисление, может быть скомпилирован отдельно от самого перечисления. Таким образом, он не знает во время компиляции порядковые значения, поэтому он не может создать правильный tablewitch op. Вот почему он вводит ленивую структуру SWITCH_TABLE для сопоставления доступных в настоящее время порядковых значений с локальными номерами int tablewitch.

person kan    schedule 24.10.2011
comment
Хорошее шоу! Я не знал, почему он вводит это косвенное обращение, но это прекрасно это объясняет. - person G_H; 24.10.2011

Мне кажется, что оператор switch в перечислении. Взгляните на класс перечисления, который перечисления неявно расширяются. У него есть метод ordinal, который используется для переключения. Вероятно, есть какое-то OrderType перечисление с константами LIMIT, MARKET, STOP и TAKE.

РЕДАКТИРОВАТЬ: На самом деле, я предполагаю, что было бы неплохо получить дополнительную информацию. Есть дым и зеркала, которые используются для таких вещей, как перечисления. Константа перечисления получает некоторый порядковый номер за экранами. Этот порядковый номер и есть то, что на самом деле используется во множестве конструкций. При переключении экземпляра enum компилятор фактически создает переключение на int (хорошо известная конструкция, которая существует уже некоторое время) с порядковым номером в качестве входных данных.

В ваших двух блоках кода происходит следующее: первый устанавливает «таблицу» (на самом деле просто массив) для порядковых номеров перечисления, если этого еще не произошло. Есть нулевая проверка. Если таблица пуста, она перейдет к метке _L2, чтобы выполнить заливку. В противном случае он переходит к метке _L1, которая просто возвращается. Второй блок кода (фактический оператор switch) переключает int. Тип int получается из таблицы путем получения элемента по индексу, который соответствует порядковому номеру константы enum.

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

Теперь причина, по которой все это выглядит так низкоуровнево, вместо того, чтобы просто видеть переключение на перечисление, заключается в том, что перечисления были введены в JDK 1.5, но JAD уже некоторое время не обслуживается и действительно поддерживает только декомпиляцию исходного кода до версии 1.4. Видя, как перечисления были реализованы с использованием конструкций, доступных в 1.4, декомпиляция действительно работает, но JAD не знает перечислений и поэтому не пытается представить это в более разборчивой форме.

Вот как, вероятно, выглядел второй блок кода:

switch(co.getOrderType()) { //co.getOrderType() gets the OrderType of some variable
    case MARKET : order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
                  break;
    case LIMIT : order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
                 break;
    case STOP : order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
                break;
}
person G_H    schedule 24.10.2011
comment
Меня удивляет, почему он создает таблицу и просто не использует порядковые номера перечисления напрямую (они уже ints)? - person kan; 24.10.2011

При использовании метода getDeclaredFields () API отражения на Android, если интроспектируемый тип содержит переключатель перечисления, где перечисление объявлено в другом классе, одним из возвращаемых полей будет ленивая структура SWITCH_TABLE, называемая чем-то вроде $SWITCH_TABLE$com$company$package$ClassName$EnumName.

Я использовал отражение для автоматического сопоставления полей класса с ContentValues перед сохранением в базу данных SQLite, и просто потратил на это полдня, пытаясь выяснить, почему массив, содержащий имена столбцов, всегда отключается на единицу.

person Jeshurun    schedule 21.06.2013