简体   繁体   English

兼容的Java编译器可以优化此代码吗?

[英]Can a compliant Java compiler optimize this code?

I was teaching an introductory programming course today and was walking through some simple code involving variable assignments in Java. 我今天正在教授一门入门编程课程,并且正在介绍一些涉及Java中变量赋值的简单代码。 The point of the code wasn't to show off anything particular exciting, but mostly to make sure students understood variable assignment statements. 代码的要点不是炫耀任何特别令人兴奋的东西,而是主要是为了确保学生理解变量赋值语句。

I had the following method up on the board and was tracing through it one line at a time: 我在电路板上有以下方法,并且一次只追踪一行:

private void simpleMethod() {
    int myInt = 137;
    myInt = 42;
    myInt = myInt + 1;

    /* ... code using myInt ... */
}

A student asked me whether myInt would ever actually hold the values 137 and 42 when the program ran, or if it would just jump straight to holding 43. I told the student that the code would execute each line in turn, so the variable would actually hold these intermediate values. 一个学生问我,当程序运行时, myInt是否myInt会保持值137和42,或者它是否会直接跳到持有43.我告诉学生代码将依次执行每一行,所以变量实际上是持有这些中间价值。

Honestly, though, I wasn't sure what bytecode javac would emit (completely ignoring the optimizations done by the JVM). 但老实说,我不确定javac会发出什么字节码(完全忽略了JVM所做的优化)。 Is javac (or any Java compiler) legally allowed to optimize the silly assignment statements away and to instead just directly initialize myInt to 43? 是否允许javac (或任何Java编译器)合法地优化愚蠢的赋值语句,而只是将myInt直接初始化为43?

According to javap , on my system, the above code compiled with javac produces 根据javap ,在我的系统上,用javac编译的上述代码生成

   0: sipush        137
   3: istore_1      
   4: bipush        42
   6: istore_1      
   7: iload_1       
   8: iconst_1      
   9: iadd          
  10: istore_1      
  11: return        

So there is no optimization going on here. 所以这里没有优化。 My question, though, is whether it's legal to optimize this or not, so this doesn't resolve anything. 不过,我的问题是,优化这个是否合法 ,所以这并不能解决任何问题。

The JLS specifies only the contract of observable behavior that your program produces. JLS仅指定程序生成的可观察行为的合约。 Since myInt is local, the optimization can indeed be optimized at compile time, since this would produce a behavior consistent with the spec, and there's nothing in the spec that says it's not allowed (at least, not that I found!). 由于myInt是本地的,因此优化确实可以在编译时进行优化,因为这会产生与规范一致的行为,并且规范中没有任何内容表明它是不允许的(至少,不是我发现的!)。 Chapter 1 of the spec specifies the observable-ness of the spec explicitly: This document fully specifies the (apparent) order of evaluation of expressions... . 规范的第1章明确规定了规范的可观察性: This document fully specifies the (apparent) order of evaluation of expressions... Since the apparent behavior is unchanged by constant-folding to myInt = 43 , the optimization would be consistent with the JLS. 由于通过常量折叠到myInt = 43来改变表观行为,因此优化将与JLS一致。

In fact, the compilation target of a Java application isn't even specified in the JLS. 实际上,甚至在JLS中都没有指定Java应用程序的编译目标。 Chapter 1 says that Java applications "normally" compile to the bytecode specified in the JVM spec (a separate document), but it does not require that they do so. 第1章说Java应用程序“通常”编译为JVM规范中指定的字节码(单独的文档),但并不要求它们这样做。 There are some statements that must be optimized at compile time, but myInt is not one such. 有些语句 必须在编译时进行优化,但myInt不是这样的。 Even if myInt were a field, I think the optimization would be allowed; 即使myInt是一个领域,我认为优化是允许的; the different behavior would still be valid behavior, even if myInt is volatile (since it represents one valid ordering of events). 即使myInt是volatile(因为它代表一个有效的事件排序),不同的行为仍然是有效的行为。

So, short answer, I think your student is correct; 所以,简短的回答,我认为你的学生是正确的; it's perfectly fine to optimize it to just myInt = 43 . 把它优化到myInt = 43是完全myInt = 43 That said, javac generally does very little -- virtually nothing -- in the way of optimization. 也就是说, javac在优化方面通常做得很少 - 几乎没有。 Optimizations are pretty much all done in the JIT. 优化几乎都在JIT中完成。

I believe the Java compiler is allowed to do any constant folding that it can statically determine at compile time. 我相信允许Java编译器执行任何常规折叠,它可以在编译时静态确定。

So yes, this could be optimised by javac . 所以是的,这可以通过javac进行优化。

However javac does not need to make this optimisation because the JVM JIT compiler will almost certainly do the same optimisation for you a bit further down the line. 然而, javac 不需要进行这种优化,因为JVM JIT编译器几乎肯定会为您进行相同的优化。 From that point of view, whether or not the Java -> Bytecode compiler does this optimisation is probably irrelevant in terms of impact on the actual native code executed at runtime. 从这个角度来看,Java - > Bytecode编译器是否进行此优化可能与对运行时执行的实际本机代码的影响无关。

So there is no optimization going on here. 所以这里没有优化。

This shouldn't be too surprising given Java uses dynamic compilation. 鉴于Java使用动态编译,这不应该太令人惊讶。

The JVM optimises almost all the code at runtime, this means that no matter whether you use code compiled for Java 1.0 in 1996 or Scala or JRuby, JGo etc, you get the full benefit of the optimisation to native code of your particular CPU model. JVM在运行时优化了几乎所有代码,这意味着无论您是使用1996年为Java 1.0编译的代码还是Scala或JRuby,JGo等,您都可以获得对特定CPU模型的本机代码进行优化的全部好处。

For this reason many languages have JVM implementations so they don't need to be able to produce optimal code for all the platforms the JVM runs on. 因此,许多语言都有JVM实现,因此它们不需要为运行JVM的所有平台生成最佳代码。

Although this is true, my question is whether the compiler is legally permitted to do this optimization 虽然这是事实,但我的问题是编译器是否在法律上允许进行此优化

By traditional data flow analysis (flow/transfer functions, in-sets, out-sets, gen-sets, kill-sets, etc.), specifically some-paths forward data flow , aka reaching definitions (or use-def chains)... yes. 通过传统的数据流分析(流/传递函数,插入,出集,生成集,终止集等),特别是一些路径转发数据流 ,即达到定义(或使用 - def链)。 ..是的。 Essentially, the optimizer can link each use of a variable to the definitions that reach it. 实质上,优化器可以将变量的每次使用链接到达到它的定义。

In this case, an optimizer could determine that the initial definition of myInt (=137) never reaches its use, while the other definition (=42 1 ) does reach its use since it is never redefined on any (some) path from that definition to its use. 在这种情况下,优化器可以确定myInt(= 137)的初始定义永远不会达到其使用,而另一个定义(= 42 1 )确实达到了它的用途,因为它永远不会在该定义的任何(某些)路径上重新定义它的用途。

References: 参考文献:

  • Dragon book 1ed (1986) chapter 10 龙书1ed(1986)第10章
  • Dragon book 2ed (2007) chapter 9 (9.2 specifically) 龙书2ed(2007)第9章(9.2具体)

1 - I use 42 all the time in my teaching code. 1 - 我在教学代码中一直使用42。 I bet we all do. 我打赌我们都这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM