Я разрабатываю механизм инструментирования с помощью ASM, и мне нужно перехватить вызов методов, которые получают параметры типа массива. Для этой цели я реализовал MethodVisitor
и в его visitMethodInsn
я проверяю, указывает ли параметр desc
какой-либо параметр типа массива. Если у целевого метода нет параметров типа массива, то мне делать нечего и я вставляю исходный вызов метода: super.visitMethodInsn(opcode, owner, name, desc);
С другой стороны, если целевой метод имеет параметры типа массива, то я должен выполнить определенное действие для его аргументов. Самым простым решением, которое я получил для доступа к каждому аргументу, было вызвать метод посредника с тем же дескриптором целевого метода, и в этом посреднике я могу легко получить доступ к его параметрам (соответствующим аргументам, переданным целевому методу).
Однако возникает проблема, когда целевой метод является конструктором экземпляра (<init>
). В Java new XXX()
переводится в байт-код следующим образом:
NEW XXX
DUP
INVOKESPECIAL XXXX.<init>()
В соответствии с подходом, который я объяснил выше, я перемещаю вызов INVOKESPECIAL
в метод посредника, и вновь созданный экземпляр объекта является первым аргументом этого посредника. Тем не менее, верификатор выдает ошибку для этого посредника, сообщая, что первый параметр посредника (который будет первым аргументом целевого метода — <init>
) не является «унифицированным объектом». Точнее я получил ошибку: Exception in thread "main" java.lang.VerifyError: Expecting to find unitialized object on stack”
.
Как только я разделяю байт-коды NEW
и INVOKESPECIAL
двумя разными методами, верификатор утверждает, что аргумент, переданный INVOKESPECIAL
, уже инициализирован.
Любое предложение обойти эту проблему? (пожалуйста, не отвечайте мне, чтобы избежать посредника и получить прямой доступ к аргументам в стеке, потому что не так просто дублировать и заменять аргументы, которые занимают произвольную позицию в стеке.)
obj.foo(x)
. Итак, на данный момент я заменяю этот вызов:obj.foo(x)
на:mediator$foo(obj, x)
— в данном случаеmediator$foo
— это новый статический метод в вызывающем классе. Поэтомуmediator$foo(obj, x)
делает то, что ему нужно, а затем вызывает цель:obj.foo(x)
. - person Miguel Gamboa   schedule 07.11.2012