2012-02-10 2 views
10

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

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

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

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

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

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

+2

Мне просто интересно. почему ты хочешь сделать это? Не было бы проще декомпилировать классы, изменить их и скомпилировать снова? – Luixv

+0

@Luixv: Я хочу, чтобы процесс манипуляции выполнялся автоматически во время выполнения - изменение исходного кода вручную не является вариантом, потому что преобразования не исправлены. – thkala

+0

Если вы поместите класс в 'jar', избыточный' nop' будет достаточно сжат, а сжатый размер будет не намного больше. –

ответ

3

Apache BCEL позволяет delete instructions:

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

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

+0

+1 Я еще не смотрел на BCEL, но это звучит многообещающе. Я посмотрю, как легко было бы включить в мой существующий код ... – thkala

0

Из Javassist урока:

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

+0

Я не хочу удалять метод - я хочу удалить инструкции из * внутри * метода ... – thkala

+0

К сожалению, мне плохо! Однако для полноты в учебнике также говорится: «Чтобы удалить поле или метод, вызовите removeField() или removeMethod() в CtClass. ' : S – user1205938