JVM会在每次执行时计算明显的返回值吗?

huangapple go评论67阅读模式
英文:

Will jvm evaluate a obvious return value on each execution?

问题

我确信几乎每个人都熟悉在SO上标记为Java的最低票数问题。为了完整起见,复制粘贴片段如下:

k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);

无论如何,上述片段始终返回11。因此,我的问题是:JVM是否会在每次调用时计算这种/类似的荒谬表达式?

英文:

I am sure almost everybody is familiar with the most downvoted question(java tagged) on SO. Copy pasting the snippet for completeness:

k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);

Above snippet always returns 11 no matter what. So my question is: will jvm evaluate this/similar madness on each invocation?

答案1

得分: 2

我不知道这是否算作一个答案,但似乎 JVM 可以证明不需要进行评估:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 20, time = 20)
@Measurement(iterations = 20, time = 20)
public class MostDownVoted {

    public static void main(String[] args) throws Exception {
        Options opt = new OptionsBuilder()
            .include(MostDownVoted.class.getSimpleName())
            .build();

        new Runner(opt).run();
    }

    @State(Scope.Benchmark)
    public static class Holder {

        int k;
        int i;
        int j;

        @Setup(Level.Iteration)
        public void setUp() {
            k = ThreadLocalRandom.current().nextInt();
            i = ThreadLocalRandom.current().nextInt();
            j = ThreadLocalRandom.current().nextInt();
        }

    }

    @Fork(1)
    @Benchmark
    public int test1(Holder h) {
        h.k = (h.j = (h.i = 0) + 2) + 1;
        return h.i |= h.j |= h.k |= (h.j += h.i) - -(h.k++ + h.k) - -(h.i = +h.j);
    }

    @Fork(1)
    @Benchmark
    public int test2(Holder h) {
        return 11;
    }

    @Benchmark
    @Fork(value = 1, jvmArgsAppend = "-XX:TieredStopAtLevel=1")
    public int test3(Holder h) {
        h.k = (h.j = (h.i = 0) + 2) + 1;
        return h.i |= h.j |= h.k |= (h.j += h.i) - -(h.k++ + h.k) - -(h.i = +h.j);
    }

}

结果显示,一旦 C2 编译器介入,与 return 11 的结果相当:

MostDownVoted.test1  avgt   20  2.816 ± 0.003  ns/op
MostDownVoted.test2  avgt   20  2.122 ± 0.016  ns/op
MostDownVoted.test3  avgt   20  3.979 ± 0.758  ns/op
英文:

I don't know if this counts as an answer, but it seems that the JVM can prove that no evaluation is needed:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 20, time = 20)
@Measurement(iterations = 20, time = 20)
public class MostDownVoted {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(MostDownVoted.class.getSimpleName())
.build();
new Runner(opt).run();
}
@State(Scope.Benchmark)
public static class Holder {
int k;
int i;
int j;
@Setup(Level.Iteration)
public void setUp() {
k = ThreadLocalRandom.current().nextInt();
i = ThreadLocalRandom.current().nextInt();
j = ThreadLocalRandom.current().nextInt();
}
}
@Fork(1)
@Benchmark
public int test1(Holder h) {
h.k = (h.j = (h.i = 0) + 2) + 1;
return h.i |= h.j |= h.k |= (h.j += h.i) - -(h.k++ + h.k) - -(h.i = +h.j);
}
@Fork(1)
@Benchmark
public int test2(Holder h) {
return 11;
}
@Benchmark
@Fork(value = 1, jvmArgsAppend = "-XX:TieredStopAtLevel=1")
public int test3(Holder h) {
h.k = (h.j = (h.i = 0) + 2) + 1;
return h.i |= h.j |= h.k |= (h.j += h.i) - -(h.k++ + h.k) - -(h.i = +h.j);
}
}

The results show that once C2 compiler kicks in, the results with return 11 are on par with what you have :

MostDownVoted.test1  avgt   20  2.816 ± 0.003  ns/op
MostDownVoted.test2  avgt   20  2.122 ± 0.016  ns/op
MostDownVoted.test3  avgt   20  3.979 ± 0.758  ns/op

huangapple
  • 本文由 发表于 2020年7月25日 00:34:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63077785.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定