JDK-6661247 : Internal bug in 32-bit HotSpot optimizer while bit manipulations
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp,windows_vista
  • CPU: x86
  • Submitted: 2008-02-09
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 Other
6u10Fixed hs11Fixed
Related Reports
Duplicate :  
Relates :  
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b24)
Java HotSpot(TM) Client VM (build 12.0-b01, mixed mode, sharing)

Microsoft Windows [Version 6.0.6000]
(Vista x64)

Unfortunately, I cannot send the simple test illustrating a bug. Obviously, the bug arises only in a complex code, for example, in our application.

Below is the link to 1MB jar-file, containing our libraries and tests:

Please download this jar and run the following test (maybe, with another path to java.exe):

"C:\Program Files (x86)\Java\jdk1.7.0\jre\bin\java" -ea -server -cp algorithm-lib-plus-demo.jar -Xmx200m -Dnet.algart.arrays.globalMemoryModel=BUFFER net.algart.arrays.demo.MainOperationsTest boolean 1000 1000 1 1 5

This test checks our complex algorithmic procedures, containing intensive manipulations with bits, packed into LongBuffer (1000 bits packed into 16 LongBuffer elements, 1000 passes). The sequence of operations is random, but the initial randseed is set via the 5th argument of this test (1), so every call leads to the same results.

When called by 32-bit java 1.7.0-ea-b24, this test prints an error message:

(5)  Testing "buffer().map" method, changing + forcing...
java.lang.AssertionError: The bug in setData found in test #455: destPos = 21, count = 887, error found at 928
        at net.algart.arrays.demo.MainOperationsTest.testBufferMapping(Unknown Source)
        at net.algart.arrays.demo.MainOperationsTest.testElementType(Unknown Source)
        at net.algart.arrays.demo.MainOperationsTest.testAll(Unknown Source)
        at net.algart.arrays.demo.MainOperationsTest.main(Unknown Source)
(This message should inform about a bug in our setData method.)

However, if we call this test without "-server" key or with "-Xint" key, or under 64-bit version of java 1.7.0-ea-b24, or under java 1.6.0_02, the test works normally and do not find any errors.

But: 32-bit java 1.6.0_04 (with -server key) also cannot perform this test!

I detected analogous bugs with bit manipulations under previous releases of Java 1.7.0-ea, on Windows XP SP2. The thorough investigations shew that sometimes 1 bit in a long bit array (packed into a direct LongBuffer) is processed incorrectly. It is probably a new bug, appeared in JVM while your latest optimizations.

If you need, we may send you the source files, but they are large and complex enough.



Please download our JAR and run the test listed above.

Expected: identical behaviour (excepting the speed) under all versions of JVM and regardless of "-server" or "-Xint" keys
Actual: under 32-bit versions of java 1.7.0-ea-b24 and java 1.6.0_04-b12, with -server key, this test "detects a bug" in my algorithms, really, I think - in the HotSpot optimizer.
This bug can be reproduced always.

SUGGESTED FIX repo: /net/jano2.sfbay/export2/hotspot/hg/hotspot-comp.clean changeset: 53:b683f557224b user: never date: Wed Mar 19 15:14:36 2008 -0700 description: 6661247: Internal bug in 32-bit HotSpot optimizer while bit manipulations Summary: copy elimination of a constant value results in incorrect execution Reviewed-by: kvn, sgoldman, rasbold files: src/share/vm/opto/chaitin.hpp src/share/vm/opto/postaloc.cpp test/compiler/6661247/Test.java

WORK AROUND Reducing the register pressure in your code might help. From looking at the code in the other bug you filed you might consider recoding your loop for packing values. It might seem like not using a loop for the packing would make the code run better but it's such a big chunk of code with so many unique constants it might be making it worse. I recoded the pack routine as a pair of loops and it performs maybe 15% better plus to doesn't trigger our bug. int low = 0; int bit = 1; for (int i = 0; i < 32; i++) { if (src[srcPos + i]) low |= bit; bit <<= 1; } int high = 0; bit = 1; for (int i = 32; i < 64; i++) { if (src[srcPos + i]) high |= bit; bit <<= 1; } srcPos += 64; Handling the high and low halves separately is reasonable since operations on longs aren't the best in 32 bit jvms. In general there isn't a good workaround for this bug but modifying your source may make it go away.

EVALUATION This is a bug in post allocation copy removal for constants introduced by the change for 5032515. There's some confusion between the value we found and the node which defined that value that results in us skipping over a def during elimination. This causes us to have the wrong register state so we think a register is live when it's not. It's a somewhat unusual case to have a rematerializable constant spilled instead of being rematerialized. I think it occurs because of the high register pressure in the unrolled body of the loop.

SUGGESTED FIX diff -r a61af66fc99e src/share/vm/opto/postaloc.cpp --- a/src/share/vm/opto/postaloc.cpp Sat Dec 01 00:00:00 2007 +0000 +++ b/src/share/vm/opto/postaloc.cpp Wed Feb 13 17:56:21 2008 -0800 @@ -253,7 +253,8 @@ int PhaseChaitin::elide_copy( Node *n, i // nodes can represent the same constant so the type and rule of the // MachNode must be checked to ensure equivalence. // -bool PhaseChaitin::eliminate_copy_of_constant(Node* val, Block *current_block, +bool PhaseChaitin::eliminate_copy_of_constant(Node* val, Node* n, + Block *current_block, Node_List& value, Node_List& regnd, OptoReg::Name nreg, OptoReg::Name nreg2) { if (value[nreg] != val && val->is_Con() && @@ -269,12 +270,12 @@ bool PhaseChaitin::eliminate_copy_of_con // Since they are equivalent the second one if redundant and can // be removed. // - // val will be replaced with the old value but val might have + // n will be replaced with the old value but n might have // kills projections associated with it so remove them now so that // yank_if_dead will be able to elminate the copy once the uses // have been transferred to the old[value]. - for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { - Node* use = val->fast_out(i); + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* use = n->fast_out(i); if (use->is_Proj() && use->outcnt() == 0) { // Kill projections have no users and one input use->set_req(0, C->top()); @@ -521,7 +522,7 @@ void PhaseChaitin::post_allocate_copy_re // then 'n' is a useless copy. Do not update the register->node // mapping so 'n' will go dead. if( value[nreg] != val ) { - if (eliminate_copy_of_constant(val, b, value, regnd, nreg, OptoReg::Bad)) { + if (eliminate_copy_of_constant(val, n, b, value, regnd, nreg, OptoReg::Bad)) { n->replace_by(regnd[nreg]); j -= yank_if_dead(n,b,&value,&regnd); } else { @@ -549,7 +550,7 @@ void PhaseChaitin::post_allocate_copy_re nreg_lo = tmp.find_first_elem(); } if( value[nreg] != val || value[nreg_lo] != val ) { - if (eliminate_copy_of_constant(n, b, value, regnd, nreg, nreg_lo)) { + if (eliminate_copy_of_constant(val, n, b, value, regnd, nreg, nreg_lo)) { n->replace_by(regnd[nreg]); j -= yank_if_dead(n,b,&value,&regnd); } else {