Удаление инструкций из Java-байт-кода

Я использовал Javassist для динамического управления классами по мере их загрузки. Хотя добавление кода в метод относительно просто с помощью Javassist, я не смог найти способ удалить код.

В это время я имитирую удаление кода, используя команды nop для замены целых кодов операций и любых параметров. Однако я считаю, что это в основном хак:

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

  • Конечный результат заполняется инструкциями nop. В то время как JVM должен оптимизировать их без какого-либо влияния на производительность, полученный байт-код по-прежнему довольно неэлегантен и больше, чем он должен быть. Это скорее проблема эстетики, но это все еще нужно рассмотреть.

К сожалению, просто сдвинуть части массива байт-кода для закрытия разрыва недостаточно - любые ссылки на перемещенный код (например, индексы инструкций ветвления) также должны быть обновлены.

Можно ли удалить инструкции с помощью Javassist? Альтернативно, есть ли библиотека манипулирования байт-кодами, которая позволила бы мне сделать это легко, без необходимости разбирать сам байт-код?

Ответ 1

Apache BCEL позволяет удалить инструкции

Удаление инструкций также очень просто; все инструкции и содержащиеся инструкции в заданном диапазоне удаляются из списка команд и удаляются. Однако метод delete() может вызывать исключение TargetLostException, когда есть указатели инструкций, все еще ссылающиеся на одну из удаленных инструкций. Пользователь вынужден обрабатывать такие исключения в предложении try-catch и перенаправлять эти ссылки в другом месте.

Вы также можете найти пример в руководстве.

Ответ 2

Из учебника javassist:

Javassist не позволяет удалить метод или поле, но позволяет изменить имя. Поэтому, если метод больше не нужен, его следует переименовать и изменить как частный метод, вызвав setName() и setModifiers(), объявленные в CtMethod.