Работа с Try / Catch Exceptions в байт-коде Java? («Высота стека несовместима») - PullRequest
6 голосов
/ 13 декабря 2011

Я пытаюсь выполнить обработку ошибок в байт-коде Java. Сначала я попытался реализовать некоторые подпрограммы типа «ловушка», в которых я проверял бы состояние ошибки и переходил к соответствующей подпрограмме, что-то вроде:

  iconst_1
  iconst_0
  dup
  ifeq calldiverr
  goto enddivtest
calldiverr:
  jsr divError
enddivtest:
  idiv

...More instructions...

divError:
  getstatic java/lang/System/out Ljava/io/PrintStream;
  ldc "Oh dear you divided by 0!"
  invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V

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

Возможно, использование исключений - лучший способ обойти это?

Из некоторых поисков я обнаружил, что вы можете создавать экземпляры классов Exception и инициализировать их что-то вроде:

new java/lang/Exception
dup
ldc "exception message!"
invokespecial java/lang/Exception/<init>(Ljava/lang/String;)V

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

Однако меня смущает именно то, как ловятся исключения. Кажется, есть волшебная «Таблица исключений», которая склеивает создание и отлов исключений, но я не знаю, как определить одно из них при написании байт-кода с нуля (и при сборке с использованием Jasmin). Может кто-нибудь сказать мне секрет создания таблицы исключений? И, возможно, приведите пример обработки исключений, которая будет собираться с помощью jasmin?

Ответы [ 3 ]

2 голосов
/ 13 декабря 2011

В конце концов, я нашел лучшее решение, чем jsr - определение метода с использованием .method в Jasmin. Я просто использовал invokestatic для вызова моего обработчика ошибок, как только обнаружил ошибку.

Для тех, кто ищет фактическую обработку исключений - я думаю, что определение таблицы исключений в Jasmin может быть сделано с помощью .catch, но я не рассматривал это, поскольку определение метода решило мою проблему.

Edit:

В конце концов мне пришлось взглянуть на .catch, и я обнаружил, что им действительно легко пользоваться. Это задокументировано здесь .

0 голосов
/ 13 декабря 2011

Правила проверки jsr довольно сложны, и, как отметил Том, код операции устарел.Так что этого лучше избегать.

Моя память на jsr немного нечеткая, но ...

(обновлено) В проверке байт-кода Java есть правило, согласно которому два потока управления объединяются вместеглубина стека должна быть одинаковой на обеих ветвях.Подпрограммы jsr освобождаются от этого правила до точки - несколько точек исключения с разной глубиной стека могут "достигать" одной и той же подпрограммы jsr, но чистое изменение глубины стека от jsr записи подпрограммы до последующей retдолжен быть равен нулю (или фактически минус 1, поскольку причина исключения всегда выдвигается при входе в процедуру).

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

(И я, несомненно, все еще кое-что неправильно понял, но это лучшийЯ могу сделать.)

(Я не совсем понимаю, как вы планируете "обойти" вашу проблему jsr с исключениями.)

(Кроме того, Sun сделала запись байт-коданамного сложнее с 4 или 5 (не помню, какой), что делает практически невозможным ручное кодирование байт-кодов.Они сделали это, потому что они не знали, как сделать проверку достаточно быстро, чтобы иначе победить верификатор IBM, но это другоевопрос.)

0 голосов
/ 13 декабря 2011

Прежде всего стоит отметить, что файлы классов из версии 51.0 могут не содержать инструкцию jsr.Повторите код или используйте метод.

В каждой точке в байт-коде должен быть известен статический тип каждого элемента в кадре.Каждый кадр не является стеком вызовов.

Как правило, вы не хотите играть с огромными большими стеками.Храните временные файлы в локальных переменных, чтобы упростить задачу.

Если выброшено исключение, то, очевидно, во фрейме могло быть содержимое из любого места, которое могло бы сгенерировать исключение.Таким образом, содержимое отбрасывается и заменяется исключением.В любом случае вы не сможете вернуться и возобновить использование содержимого фрейма.

...