JVM字节码,我怎样才能找到局部变量的类型?

时间:2016-01-19 00:16:06

标签: java bytecode

我正在研究Jetbrains的a fork FernFlower,我一直在为它添加一些小改进。

有一件事让我对FernFlower感到恼火的是,它基于bpush / spush等中的值来定位局部变量的类型。而Jode和Procyon以某种方式找到了找到局部变量原始值的方法。 / p>

这是原始源代码。

gnuplot -e persist "set title 'Resource monitor' ; set timefmt '%y/%m/%d-%H:%M:%S' ; set xdata time ; set xlabel 'TIME' ; set ylabel 'PERCENT' set yrange [0:101]" -e "plot '${cpuResFile}' using 1:2 title 'CPU' smooth Bezier, '${memResFile}' using 1:2 title 'MEM' smooth Bezier" &

使用FernFlower进行反编译时,会输出:

public static void main(String[] args) throws Exception {
    int hello = 100;
    char a2 = 100;
    short y1o = 100;
    int hei = 100;

    System.out.println(a2+" "+y1o+", "+hei+", "+hello);
}

但是当使用Jode / Procyon进行反编译时,它会输出原始的局部变量类型:

public static void main(String[] args) throws Exception {
    byte hello = 100;
    char a2 = 100;
    byte y1o = 100;
    byte hei = 100;
    System.out.println(a2 + " " + y1o + ", " + hei + ", " + hello);
}

我想知道这怎么可能,因为我认为在编译时没有存储局部变量类型信息?如何向FernFlower添加相同的功能?

2 个答案:

答案 0 :(得分:4)

.class个文件可选地包含“LocalVariableTable”属性以用于调试目的。如果您调用命令javap -l <Class>.class,则可以看到数据是否存在。

答案 1 :(得分:2)

因此,在查看和调试之后,我发现由于某种原因,FernFlower决定完全忽略LocalVariableTable中的一些数据。

这是用于解码LocalVariableTable的蕨类原始代码:

@Override
public void initContent(ConstantPool pool) throws IOException {
    DataInputFullStream data = stream();

    int len = data.readUnsignedShort();
    if (len > 0) {
        mapVarNames = new HashMap<Integer, String>(len);
        mapVarTypes = new HashMap<Integer, String>(len);
        for (int i = 0; i < len; i++) {
            int start  = data.readUnsignedShort();
            int end    = start + data.readUnsignedShort();
            int nameIndex = data.readUnsignedShort();
            int typeIndex = data.readUnsignedShort();
            int varIndex = data.readUnsignedShort();
            mapVarNames.put(varIndex, pool.getPrimitiveConstant(nameIndex).getString());
            mapVarTypes.put(varIndex, pool.getPrimitiveConstant(typeIndex).getString());
        }
    } else {
        mapVarNames = Collections.emptyMap();
        mapVarTypes = Collections.emptyMap();
    }
}

如果您需要类型信息,则需要添加以下内容:

{{1}}

它现在输出与Jode相同的代码,并带有适当的变量类型:)

我想知道为什么FernFlower选择忽略这些信息。