2016-02-23 1 views
1

Я где-то читал, что когда когда-либо метод вызывается «invokevirtual», ссылка на объект извлекается из верхней части стек, за которым следуют аргументы. Мне нужно как-то распечатать ссылку на объект. Является ли это возможным?Есть ли способ распечатать объект ref, который вызвал метод instance/Static, используя инструментарий с байтовым кодом

+0

Что это за «объект ref, который называется ...» вашего названия должен быть? Почему вы упоминаете 'static' методы в своем названии, когда вы ссылаетесь на' invokevirtual' только в вопросе? – Holger

+0

Я действительно изучал динамическое поведение класса. и предполагая, что каждый вызов метода в программе java преобразуется в invokevirtual/invokestatic в байт-код. например invokevirtual # 38, где # 38 ссылается на некоторый идентификатор в постоянном пуле. Поэтому просто хотелось узнать, как можно получить информацию о # 38 во время выполнения. –

+0

Ваш комментарий описывает совсем другую вещь, чем ваш вопрос. Ваш вопрос касается ссылки на объект в стеке операндов, тогда как ваш комментарий относится к индексу в пул констант, встроенный в инструкцию. Итак, теперь у нас есть три несовместимые вещи, ваше название, ваш вопрос и ваш комментарий. Ответ на последний: вы можете найти эту информацию в том же месте, где вы получили «# 38». – Holger

ответ

1

Итак, я не собираюсь делать это за вас, потому что фактический код раздражает и утомителен, и если вы действительно искренне заинтересованы, вы должны научиться самому это делать. Но я постараюсь быть полезным и предоставить вам какое-то направление.

Во-первых, вы захотите прочитать ASM tutorials here.

Формат байтового кода, который я собираюсь написать ниже, поступает от ASMIfier, потому что это намного более ясно. Я собираюсь полностью игнорировать javap, потому что он еще более педантичен и детализирован, но если вы хотите знать, что он на самом деле показывает вам, тогда вы должны прочитать о Java ClassFile format.

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

Итак, вкратце из того, что вы собираетесь делать. Вы захотите написать ClassWriter, который ищет экземпляры кода операции INVOKEVIRTUAL.

invokevirtual выводит значения из стека в обратном порядке, поэтому последний параметр сначала и объект, который вы вызываете против последнего. # 38, на который вы ссылаетесь, также не является объектом, его ссылкой на постоянный пул, который содержит имя метода и пару дескрипторов метода, которая используется как метаданные, поскольку JVM является типичным.

Давайте предположим, что у вас есть этот код:

пакет образца;

public class JavaSimpleHelloWorld { 
    public static void main(String[] args) { 

     System.out.println("Hello World"); 
    } 
} 

Если запустить ASMIFier против него, вы получите что-то вроде этого для всего основного метода (режущей контекст вниз для краткости)

public static main([Ljava/lang/String;)V 
    L0 
    LINENUMBER 6 L0 
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
    LDC "Hello World" 
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V 
    L1 
    LINENUMBER 7 L1 
    RETURN 
    L2 
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0 
    MAXSTACK = 2 
    MAXLOCALS = 1 

так, вы реализуете какое-то статическая свалку метод (public static final dump (Object o)) и написать посетителя класса, который реорганизует ваш байт-код.

Вы можете использовать дескриптор метода, чтобы выяснить, насколько глубоко в инструкциях толкового стека (ALOAD, LDC) вам нужно вставить DUP/INVOKE для печати объекта объекта методов. Например, дескриптор метода для System.out.println является [Ljava/lang/String;] V. Это означает, что метод принимает массив строк и возвращает void. Поэтому вам нужно вернуться в стек, чтобы найти цель объекта. Ваш байт-код будет, в свою очередь, выглядеть так:

Счастливый байт код сплетения.

public static main([Ljava/lang/String;)V 
    L0 
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
    DUP 
    INVOKESTATIC my/staticutil/ClassThatDumps.dump (Ljava/lang/Object;)V 
    LDC "Hello World" 
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V 
    RETURN 
    L1 
    LOCALVARIABLE args [Ljava/lang/String; L0 L1 0 
    MAXSTACK = 2 
    MAXLOCALS = 1 
Смежные вопросы