/* * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.openjdk; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @Fork(1) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) public class BooleanNegate { /* Credits are due to Henrik Johansson (https://twitter.com/dahankzter) for pointing this out. Trying to disprove the PMD rule: http://pmd.sourceforge.net/pmd-5.2.1/pmd-java/rules/java/controversial.html#BooleanInversion The rule is inspired by Dr. Heinz Kabutz article here: http://www.javaspecialists.eu/archive/Issue042.html However, this benchmark running on i7-4790K, JDK 8u40-ea, Linux x86_64 yields: Benchmark Mode Samples Score Error Units o.o.BooleanNegate.assignBitwise avgt 5 1.516 ± 0.024 ns/op o.o.BooleanNegate.assignNegation avgt 5 1.515 ± 0.009 ns/op o.o.BooleanNegate.assignTernary avgt 5 1.513 ± 0.014 ns/op o.o.BooleanNegate.baseline avgt 5 0.630 ± 0.010 ns/op All three tests are yielding the same score, because they are generated as the same instruction sequence, see below. All use "xor $x, 1" to negate the boolean value. If there is a JDK which has either of three tests faster/slower, that's a code generation performance bug. */ private boolean x = true; @Benchmark public boolean baseline() { return x; } /* 0x00007f2555191212: movzbl 0x94(%rdi),%r10d 0x00007f255519121a: add $0x1,%rbp 0x00007f255519121e: test %eax,0x173f4ddc(%rip) 0x00007f2555191224: test %r10d,%r10d 0x00007f2555191227: jne 0x00007f25551911e0 0x00007f2555191229: movzbl 0xd2(%rcx),%r10d 0x00007f2555191231: movzbl 0xc(%r11),%edx ; get $x 0x00007f2555191236: xor $0x1,%edx ; BOOLEAN NEGATE 0x00007f2555191239: mov %dl,0xc(%r11) ; store $x 0x00007f255519123d: movzbl 0xd3(%rcx),%r8d 0x00007f2555191245: cmp %r8d,%edx 0x00007f2555191248: jne 0x00007f2555191212 0x00007f255519124a: cmp %r10d,%edx 0x00007f255519124d: mov $0x1,%r8d 0x00007f2555191253: cmovne %r9d,%r8d 0x00007f2555191257: test %r8d,%r8d 0x00007f255519125a: je 0x00007f2555191212 */ @Benchmark public boolean assignNegation() { x = !x; return x; } /* 0x00007f84dd192a80: movzbl 0x94(%rdx),%r10d 0x00007f84dd192a88: add $0x1,%rbp 0x00007f84dd192a8c: test %eax,0x1777956e(%rip) 0x00007f84dd192a92: test %r10d,%r10d 0x00007f84dd192a95: jne 0x00007f84dd192a47 0x00007f84dd192a97: movzbl 0xd2(%rcx),%r10d 0x00007f84dd192a9f: movzbl 0xc(%r11),%edi ; get $x 0x00007f84dd192aa4: xor $0x1,%edi ; BOOLEAN NEGATE 0x00007f84dd192aa7: mov %dil,0xc(%r11) ; store $x 0x00007f84dd192aab: movzbl 0xd3(%rcx),%r8d 0x00007f84dd192ab3: cmp %r8d,%edi 0x00007f84dd192ab6: jne 0x00007f84dd192a80 0x00007f84dd192ab8: cmp %r10d,%edi 0x00007f84dd192abb: mov $0x1,%r10d 0x00007f84dd192ac1: cmovne %r9d,%r10d 0x00007f84dd192ac5: test %r10d,%r10d 0x00007f84dd192a80 je 0x00007f84dd192a80 */ @Benchmark public boolean assignBitwise() { x ^= true; return x; } /* 0x00007feac918a152: movzbl 0x94(%rdx),%r10d 0x00007feac918a15a: add $0x1,%rbp 0x00007feac918a15e: test %eax,0x16351e9c(%rip) 0x00007feac918a164: test %r10d,%r10d 0x00007feac918a167: jne 0x00007feac918a120 0x00007feac918a169: movzbl 0xd2(%rcx),%r10d 0x00007feac918a171: movzbl 0xc(%r11),%edi ; get $x 0x00007feac918a176: xor $0x1,%edi ; BOOLEAN NEGATE 0x00007feac918a179: mov %dil,0xc(%r11) ; store $x 0x00007feac918a17d: movzbl 0xd3(%rcx),%r8d 0x00007feac918a185: cmp %r8d,%edi 0x00007feac918a188: jne 0x00007feac918a152 0x00007feac918a18a: cmp %r10d,%edi 0x00007feac918a18d: mov $0x1,%r10d 0x00007feac918a193: cmovne %r9d,%r10d 0x00007feac918a197: test %r10d,%r10d 0x00007feac918a19a: je 0x00007feac918a152 */ @Benchmark public boolean assignTernary() { x = x ? false : true; return x; } }