Как автоматически получить исходный код Java для данной позиции байт-кода?

Я экспериментирую с инструментом, который выполняет статический анализ. Инструмент работает с байт-кодом, а не с исходным кодом. (Тем не менее, у меня есть исходный код).

Инструмент выводит несколько номеров строк из байт-кода, и теперь мне нужен простой способ обратного сопоставления с исходным кодом. Netbeans/Eclipse делают это все время (когда я нажимаю на метод во включенной библиотеке, IDE переводит меня к источнику (если он доступен)), поэтому я знаю, что это возможно. Я просто не мог найти способ сделать это.

В качестве примера рассмотрим следующую программу hello world:

package mypackage;
import java.io.*;
class MyMainClass {
  public static void main(String[] args) { 
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
    String name0 = "Alice";
    String name1 = "Bob";
    try {
        name0 = in.readLine();
    }
    catch(Exception e) {
        System.out.println("Caught an exception!"); 
    }       
    System.out.println("Hello " + name0 + "!"); 
    System.out.println("Hello " + name1 + "!"); 
  }
}

Сгенерированный байт-код (полученный из javap):

Compiled from "MyMainClass.java"
class mypackage.MyMainClass extends java.lang.Object{
mypackage.MyMainClass();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class java/io/BufferedReader
   3:   dup
   4:   new     #3; //class java/io/InputStreamReader
   7:   dup
   8:   getstatic       #4; //Field java/lang/System.in:Ljava/io/InputStream;
   11:  invokespecial   #5; //Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;)V
   14:  invokespecial   #6; //Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
   17:  astore_1
   18:  ldc     #7; //String Alice
   20:  astore_2
   21:  ldc     #8; //String Bob
   23:  astore_3
   24:  aload_1
   25:  invokevirtual   #9; //Method java/io/BufferedReader.readLine:()Ljava/lang/String;
   28:  astore_2
   29:  goto    42
   32:  astore  4
   34:  getstatic       #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   37:  ldc     #12; //String Caught an exception!
   39:  invokevirtual   #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   42:  getstatic       #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   45:  new     #14; //class java/lang/StringBuilder
   48:  dup
   49:  invokespecial   #15; //Method java/lang/StringBuilder."<init>":()V
   52:  ldc     #16; //String Hello
   54:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   57:  aload_2
   58:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   61:  ldc     #18; //String !
   63:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   66:  invokevirtual   #19; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   69:  invokevirtual   #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   72:  getstatic       #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   75:  new     #14; //class java/lang/StringBuilder
   78:  dup
   79:  invokespecial   #15; //Method java/lang/StringBuilder."<init>":()V
   82:  ldc     #16; //String Hello
   84:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   87:  aload_3
   88:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   91:  ldc     #18; //String !
   93:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   96:  invokevirtual   #19; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   99:  invokevirtual   #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   102: return
  Exception table:
   from   to  target type
    24    29    32   Class java/lang/Exception


}

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

<mypackage.MyMainClass> 39, 69, 99

Они соответствуют номерам строк байт-кода. Вручную я могу вычислить, что строки должны соответствовать следующим строкам в исходном коде:

System.out.println("Caught an exception!"); 
System.out.println("Hello " + name0 + "!"); 
System.out.println("Hello " + name1 + "!"); 

Однако мне нужно автоматизировать этот процесс. Любая помощь будет оценена по достоинству.

8
задан Ciro Santilli 新疆改造中心法轮功六四事件 24 June 2015 в 17:03
поделиться