FULL PRODUCT VERSION :
----------------------------------------
Versions:
------------------------------
javac.exe version:
javac 1.8.0_20
--------------------
java.exe version:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
--------------------
javap.exe version:
1.8.0_20
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
Any other OSs
A DESCRIPTION OF THE PROBLEM :
----------------------------------------
Overview and description:
------------------------------
As this code
int a = 10, b = 20;
a ^= (b ^= (a ^= b));
should swap the values of "a" and "b", actually makes the compiler spit out wrong bytecode,
hence you get different results in the end.
Results:
a = 0
b = 10
Where this method
int a = 10, b = 20;
a ^= b;
b ^= a;
a ^= b;
returns the correct values.
Results:
a = 20
b = 10
ADDITIONAL REGRESSION INFORMATION:
----------------------------------------
Versions:
------------------------------
javac.exe version:
javac 1.8.0_20
--------------------
java.exe version:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
--------------------
javap.exe version:
1.8.0_20
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the given code. To decompile the bytecode and watch its assembly, just use javap -c <filename>
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Swapping values of the variables "a" and "b" for example
a = 20
b = 10
ACTUAL -
a = 0
b = 10
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class BugSwap
{
public static void main(String args[])
{
int a = 10, b = 20;
// Swaps values (Not correctly working)
a ^= (b ^= (a ^= b));
System.out.println("a = "+a+"; b = "+b);
}
}
/*
----------------------------------------
Decompiled bytecode from the incorrect working method (partial):
------------------------------
; BugSwap.class (partial view of the main() method)
; int a = 10, b = 20;
bipush 10 ; Push 10 into stack (Int)
istore_1 ; Store into 1st variable (Int)
bipush 20 ; Push 20 into stack (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= (b ^= (a ^= b));
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_1 ; Store into 1st variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_2 ; Store into 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; Results:
; a = 0
; b = 10
;
; Incorrect!
----------------------------------------
Decompiled bytecode from the correct working method (partial):
------------------------------
; AlternativeSwap.class (partial view of the main() method)
; int a = 10, b = 20;
bipush 10 ; Push 10 into stack (Int)
istore_1 ; Store into 1st variable (Int)
bipush 20 ; Push 20 into stack (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= b;
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; b ^= a;
iload_2 ; Load from 2nd variable (Int)
iload_1 ; Load from 1st variable (Int)
ixor ; XOR (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= b;
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; Results:
; a = 20
; b = 10
;
; Correct!
----------------------------------------
Decompiled bytecode and edited from the former incorrect working method (partial):
------------------------------
; EditedBugSwap.class (partial view of the main() method, which is edited)
; int a = 10, b = 20;
bipush 10 ; Push 10 into stack (Int)
istore_1 ; Store into 1st variable (Int)
bipush 20 ; Push 20 into stack (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= (b ^= (a ^= b));
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_1 ; Store into 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_2 ; Store into 2nd variable (Int)
iload_1 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; Results:
; a = 20
; b = 10
;
; Correct!
*/
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
a ^= b;
b ^= a;
a ^= b;
/*
----------------------------------------
Conclusion:
------------------------------
Loading the old values in the first place may work correctly,
if the stack values are synced with the variables,
otherwise you may end up using the incorrect values within the stack,
because the variables are being manipulated in runtime,
hence the alternative assembly code (3rd one provided as comment in source code) works as intended.
Best regards
Ethem Kurt
*/
----------------------------------------
Versions:
------------------------------
javac.exe version:
javac 1.8.0_20
--------------------
java.exe version:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
--------------------
javap.exe version:
1.8.0_20
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
Any other OSs
A DESCRIPTION OF THE PROBLEM :
----------------------------------------
Overview and description:
------------------------------
As this code
int a = 10, b = 20;
a ^= (b ^= (a ^= b));
should swap the values of "a" and "b", actually makes the compiler spit out wrong bytecode,
hence you get different results in the end.
Results:
a = 0
b = 10
Where this method
int a = 10, b = 20;
a ^= b;
b ^= a;
a ^= b;
returns the correct values.
Results:
a = 20
b = 10
ADDITIONAL REGRESSION INFORMATION:
----------------------------------------
Versions:
------------------------------
javac.exe version:
javac 1.8.0_20
--------------------
java.exe version:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
--------------------
javap.exe version:
1.8.0_20
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the given code. To decompile the bytecode and watch its assembly, just use javap -c <filename>
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Swapping values of the variables "a" and "b" for example
a = 20
b = 10
ACTUAL -
a = 0
b = 10
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class BugSwap
{
public static void main(String args[])
{
int a = 10, b = 20;
// Swaps values (Not correctly working)
a ^= (b ^= (a ^= b));
System.out.println("a = "+a+"; b = "+b);
}
}
/*
----------------------------------------
Decompiled bytecode from the incorrect working method (partial):
------------------------------
; BugSwap.class (partial view of the main() method)
; int a = 10, b = 20;
bipush 10 ; Push 10 into stack (Int)
istore_1 ; Store into 1st variable (Int)
bipush 20 ; Push 20 into stack (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= (b ^= (a ^= b));
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_1 ; Store into 1st variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_2 ; Store into 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; Results:
; a = 0
; b = 10
;
; Incorrect!
----------------------------------------
Decompiled bytecode from the correct working method (partial):
------------------------------
; AlternativeSwap.class (partial view of the main() method)
; int a = 10, b = 20;
bipush 10 ; Push 10 into stack (Int)
istore_1 ; Store into 1st variable (Int)
bipush 20 ; Push 20 into stack (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= b;
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; b ^= a;
iload_2 ; Load from 2nd variable (Int)
iload_1 ; Load from 1st variable (Int)
ixor ; XOR (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= b;
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; Results:
; a = 20
; b = 10
;
; Correct!
----------------------------------------
Decompiled bytecode and edited from the former incorrect working method (partial):
------------------------------
; EditedBugSwap.class (partial view of the main() method, which is edited)
; int a = 10, b = 20;
bipush 10 ; Push 10 into stack (Int)
istore_1 ; Store into 1st variable (Int)
bipush 20 ; Push 20 into stack (Int)
istore_2 ; Store into 2nd variable (Int)
; a ^= (b ^= (a ^= b));
iload_1 ; Load from 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_1 ; Store into 1st variable (Int)
iload_2 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
dup ; Duplicate top operand into stack
istore_2 ; Store into 2nd variable (Int)
iload_1 ; Load from 2nd variable (Int)
ixor ; XOR (Int)
istore_1 ; Store into 1st variable (Int)
; Results:
; a = 20
; b = 10
;
; Correct!
*/
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
a ^= b;
b ^= a;
a ^= b;
/*
----------------------------------------
Conclusion:
------------------------------
Loading the old values in the first place may work correctly,
if the stack values are synced with the variables,
otherwise you may end up using the incorrect values within the stack,
because the variables are being manipulated in runtime,
hence the alternative assembly code (3rd one provided as comment in source code) works as intended.
Best regards
Ethem Kurt
*/