根据执行历史,给定指令的操作数堆栈大小是否不同?

时间:2016-04-26 01:35:20

标签: java bytecode jvm-bytecode

例如,对于方法

function JsonObject<T>(initializer: (json: any) => T) {
    return function (target: { new (...args: any[]): T }) {
        return null;
    }
}


@JsonObject(function (json) {
    return new Foo();
})
class Foo {
    foo: string;
}

@JsonObject(function (json) {
    // Test case: return an exact corresponding type.
    return new Bar(); // OK, as it should be
})
class Bar extends Foo {
    bar: string;
}

@JsonObject(function (json) {
    // Test case: return a derived type.
    return new Baz(); // Ok
})
class Baz extends Bar {
    baz: string;
}

public int f() { int k = 1; for (int i = 0; i < 10; i++) { k += 2; } return k; } 生成以下字节码:

javac

在标签4处,堆栈具有相同的大小(0),无论先前是哪个指令:3或16.

对于从java代码生成的字节码来说,这通常是正确的吗?

2 个答案:

答案 0 :(得分:4)

有关锑的答案的参考,请参阅 JVM specification §4.9.2. Structural Constraints(谢谢Holger!):

  
      
  • ...
  •   
  • 如果一条指令可以沿着几条不同的执行路径执行,那么操作数堆栈必须在执行指令之前具有相同的深度(§2.6.2),无论采用何种路径。
  •   

在这个答案的第一个版本中,我引用了§4.10.2.1. The Process of Verification by Type Inference,它适用于不包含StackMapTable属性(版本号为49.0或更低版本)的类文件:

  

...验证程序确保在程序中的任何给定点,无论采用何种代码路径达到该点,以下所有条件均为真:

     
      
  • 操作数堆栈的大小始终相同,并包含相同类型的值。
  •   
  • ...
  •   

答案 1 :(得分:3)

是。无论控制流如何,字节码验证都强制执行任何给定指令的堆栈大小。 (它还强制类型兼容)。因此,不仅从编译的Java派生的字节码,而且任何有效的字节码都是如此。