Name: kb87695 Date: 12/07/2000
See description after the test case
I want to report a bug that can be reproduced in SPARC. I am
using the following Java specs.
^X
java version "1.2.2"
HotSpot VM (1.0.1, mixed mode)
The VM was build using the following steps.
1. Download the source. (hotspot-1_0_1-fcs-src-sol-06_aug_1999.zip)
2. Build with gnumake optimized ( The bug is easily reproducible with
the optimized build )
3. Compile TestVP.java
4. java -XX:MaxInlineSize=6 -XX:CompileThreshold=5 -XX:-BackgroundCompilation -XX:CompileOnly=TestVP.\<init\> TestVP
The problem is in the hotspot compiler.
The optimized build is preferable as we can manipulate some debug flags
to inline String.length(), which is difficult to reproduce in the debug
or product versions.
I am also attaching the Java source code with the mail. Please let me
know, what my steps should be in order to file the bug.
The bug output is as follows:
$ java -XX:MaxInlineSize=6 -XX:CompileThreshold=5 -XX:-BackgroundCompilation -XX:CompileOnly=TestVP.\<init\> TestVP
Start test
Loop: 1
Loop: 2
Loop: 3
Exception in thread "main" java.lang.NullPointerException
<<no stack trace available>>
The right output should be (which can be got using the following options
that does not inline the String.length() method)
$ java -XX:MaxInlineSize=6 -XX:CompileThreshold=5
-XX:CompileOnly=TestVP.\<init\> TestVP
Start test
Loop: 1
Loop: 2
Loop: 3
Loop: 4
Loop: 5
Loop: 6
Loop: 7
Loop: 8
Loop: 9
Loop: 10
Java Source
/**
* 2000/11/07
* Test case to debug Hotspot compiler bug
*
* To run:
* Using regular JAVA:
* java -XX:MaxInlineSize=6 -Xcomp -XX:CompileThreshold=5 TestVP
* Using optimized build:
* java -XX:MaxInlineSize=6 -Xcomp -XX:CompileThreshold=5 -XX:CompileOnly=TestVP.\<init\> TestVP
*
* <IMPORTANT>: The testcase fails when String.length (5 bcs) is being inlined.
*
* TestVP constructor is very sensitive. Addition of printlns
* make problem disappear (String.length won't get inlined).
*/
class StringUtils
{
public static String[] dumbSplitString()
{
String[] mElements = new String [3];
mElements[0]="";
mElements[1]="hi";
mElements[2]="";
return mElements;
}
}
public class TestVP
{
//-------------------------------------
// FIELDS
//-------------------------------------
/** Set of pathname elements */
String[] mElements;
/** offset into mElements at which entry's list of pathnames start */
int mStart;
/** number of elements beginning at mElements[mStart] */
int mLength;
//-------------------------------------
// CONSTRUCTOR
//-------------------------------------
public TestVP () {
mElements = StringUtils.dumbSplitString();
mStart = 0;
mLength = mElements.length;
while (mStart < mLength && mElements[mStart].length() == 0) {
mStart++;
mLength--;
}
while (mLength > 0 && mElements[mStart + mLength - 1].length() == 0) {
mLength--;
}
//int length = mElements[mStart].length();
}
//-------------------------------------
//-------------------------------------
public static void main (String args[]) {
System.out.println ("\nStart test\n");
for (int i=1; i<=10; i++)
{
System.out.println ("Loop: " + i);
TestVP VP = new TestVP ();
}
}
}
###@###.### 2000-12-07
This problem was verified on an Ultra 10 running Solaris 7
(Review ID: 112892)
======================================================================
kevin.brown@eng 2000-12-07
The problem is in the compiler as I have studied the optoassembly of sparc as well as pa-risc. When you change the method, the intermediate representation of
the method changes and the bug is no-longer visible. The hs20 optoassembly
is fine in both sparc and pa-risc, which makes me think that there is a
bug in the shared part of the compiler code.
The problem starts immediately after the contructor for TEstVP
inlines String.length(). At this point the the register that contains the
array variable enters the loop fine and the first assignment works Ok.
However, when it returns from the loop, it puts a NULL value into the
register and this causes the problem.
attached below is the opto-assembly dump that I got from sparc. I
have commented the piece of code that I think caused the problem. My
comments start with (// comment:). Please note that the loop basicblocks
B10 to B14. The crash probably happens in B11. As I did not have a good
sparc debugger, I could not verify my hypothesis, although the pa-risc
debugger showed similar behavior.
OPTO ASSEMBLY
{method}
- klass: {other class}
- method holder: 'TestVP'
- access: 1 public
- name: '<init>'
- signature: '()V'
- max stack: 3
- max locals: 1
- code size: 117
- constants: {constant pool}
- exceptions: [I
- line numbers: [S
- local vars: [S
- exception indices: [S
0 load_local_object #0
1 invoke_special 0 <<init>> <()V>
4 load_local_object #0
5 invoke_static 1 <dumbSplitString> <()[Ljava/lang/String;>
8 put_field 2 <mElements>
11 load_local_object #0
12 push_int 0
13 put_field 3 <mStart>
16 load_local_object #0
17 load_local_object #0
18 get_field 2 <mElements>
21 array_length
22 put_field 4 <mLength>
25 branch 48
28 load_local_object #0
29 dup
30 get_field 3 <mStart>
33 push_int 1
34 arithmetic_int_add
35 put_field 3 <mStart>
38 load_local_object #0
39 dup
40 get_field 4 <mLength>
43 push_int 1
44 arithmetic_int_sub
45 put_field 4 <mLength>
48 load_local_object #0
49 get_field 3 <mStart>
52 load_local_object #0
53 get_field 4 <mLength>
56 branch_if_icmp_ge 87
59 load_local_object #0
60 get_field 2 <mElements>
63 load_local_object #0
64 get_field 3 <mStart>
67 load_array_object
68 invoke_virtual 5 <length> <()I>
71 branch_if_eq 28
74 branch 87
77 load_local_object #0
78 dup
79 get_field 4 <mLength>
82 push_int 1
83 arithmetic_int_sub
84 put_field 4 <mLength>
87 load_local_object #0
88 get_field 4 <mLength>
91 branch_if_le 116
94 load_local_object #0
95 get_field 2 <mElements>
98 load_local_object #0
99 get_field 3 <mStart>
102 load_local_object #0
103 get_field 4 <mLength>
106 arithmetic_int_add
107 push_int 1
108 arithmetic_int_sub
109 load_array_object
110 invoke_virtual 5 <length> <()I>
113 branch_if_eq 77
116 return_void
#
# void <init>( TestVP:NotNull * )
#
# R_I0 : parm 0: TestVP:NotNull *
# -- Old R_SP -- Framesize: 72 --
# R_SP+68: preserve
# R_SP+64: preserve
# R_SP+60: preserve
# R_SP+56: preserve
# R_SP+52: preserve
# R_SP+48: preserve
# R_SP+44: preserve
# R_SP+40: preserve
# R_SP+36: preserve
# R_SP+32: preserve
# R_SP+28: preserve
# R_SP+24: preserve
# R_SP+20: preserve
# R_SP+16: preserve
# R_SP+12: preserve
# R_SP+ 8: preserve
# R_SP+ 4: preserve
# R_SP+ 0: preserve
000 N198: # B1 <- BLOCK HEAD IS JUNK Loop: 0-21#0 IDom: 0/#1 Freq: 1.0e+00
000 ---- MachUEPNode ----
01c NOP # Pad for loops
020
020 B1: # B17 B2 <- BLOCK HEAD IS JUNK Loop: 0-21#0 IDom: 0/#2 Freq: 1.0e+00
020 --- MachPrologNode ----
02c CALL,static ; NOP ==> StringUtils::dumbSplitString
# TestVP::<init> @ bci:5 L0=R_I0 STK0=R_I0
# R_I0=Oop
034
034 B2: # B20 B3 <- B1 Loop: 0-21#0 IDom: 1/#3 Freq: 1.0e+00
034 STW R_O0,[[R_I0 + #8]] !ptr
038 SRL R_I0,#9,R_I1
03c SET 0xee512000,R_I2 !ptr
044 STB #0,[[R_I2 + R_I1]] !ptr
048 MOV #0,R_L0
04c STW R_L0,[[R_I0 + #12]]
050 LDUW [R_O0 + #8],R_I1 !range
054 NullCheck R_O0
054
054 B3: # B4 <- B2 Loop: 0-21#0 IDom: 2/#4 Freq: 1.0e+00
054 STW R_I1,[[R_I0 + #16]]
058 MOV R_I1,R_I2
05c NOP # Pad for loops
060
060 B4: # B9 B5 <- B3 B8 Loop: 4-8#1 IDom: 3/#5 Freq: 1.0e+01
060 SUBCC R_L0,R_I2,R_G0
064 BPCCodege B9 # 0x0b0
06c
06c B5: # B19 B6 <- B4 Loop: 4-8#1 IDom: 4/#6 Freq: 9.0e+00
06c SUBCC R_L0,R_I1,R_G0
070 BPCuCodege B19 # 0x144
078
078 B6: # B20 B7 <- B5 Loop: 4-8#1 IDom: 5/#7 Freq: 9.0e+00
078 SLL R_L0,#2,R_I3
07c ADD R_O0,R_I3,R_I3
080 LD [R_I3 + #12],R_I3 !ptr
084 LDUW [R_I3 + #16],R_I3
088 NullCheck R_I3
088
088 B7: # B9 B8 <- B6 Loop: 4-8#1 IDom: 6/#8 Freq: 9.0e+00
088 Safepoint_ # TestVP::<init> @ bci:71 L0=R_I0
# R_I0=Oop R_O0=Oop
08c SUBCC R_I3,#0,R_G0
090 BPCCodene B9 # 0x0b0
098
098 B8: # B4 <- B7 Loop: 4-8#1 IDom: 7/#9 Freq: 8.1e+00
098 ADD R_L0,#1,R_L0
09c STW R_L0,[[R_I0 + #12]]
0a0 ADD R_I2,#-1,R_I2
0a4 STW R_I2,[[R_I0 + #16]]
0a8 BPA B4 # 0x060
0b0
0b0 B9: # B10 <- B7 B4 Loop: 0-21#0 IDom: 4/#6 Freq: 1.9e+00
0b0 MOV R_O0,R_I1 !ptr
0b4 NOP # Pad for loops
0b8 NOP # Pad for loops
0bc NOP # Pad for loops
0c0
0c0 B10: # B16 B11 <- B9 B15 Loop: 10-15#1 IDom: 9/#7 Freq: 1.9e+01
0c0 LDUW [R_I0 + #16],R_I2
0c4 SUBCC R_I2,#0,R_G0
0c8 BPCCodele B16 # 0x11c
0d0
0d0 B11: # B20 B12 <- B10 Loop: 10-15#1 IDom: 10/#8 Freq: 1.7e+01
0d0 LDUW [R_I1 + #8],R_I3 !range // comment !!CRASH
0d4 NullCheck R_I1
0d4
0d4 B12: # B18 B13 <- B11 Loop: 10-15#1 IDom: 11/#9 Freq: 1.7e+01
0d4 ADD R_L0,R_I2,R_I4
0d8 ADD R_I4,#-1,R_I5
0dc SUBCC R_I5,R_I3,R_G0
0e0 BPCuCodege B18 # 0x134
0e8
0e8 B13: # B20 B14 <- B12 Loop: 10-15#1 IDom: 12/#10 Freq: 1.7e+01
0e8 SLL R_I4,#2,R_I3
0ec ADD R_I1,R_I3,R_I1
0f0 LD [R_I1 + #8],R_I1 !ptr
0f4 LDUW [R_I1 + #16],R_I1
0f8 NullCheck R_I1
0f8
0f8 B14: # B16 B15 <- B13 Loop: 10-15#1 IDom: 13/#11 Freq: 1.7e+01
0f8 Safepoint_ # TestVP::<init> @ bci:113 L0=R_I0
# R_I0=Oop
0fc SUBCC R_I1,#0,R_G0
100 BPCCodene B16 # 0x11c
108
108 B15: # B10 <- B14 Loop: 10-15#1 IDom: 14/#12 Freq: 1.5e+01
108 ADD R_I2,#-1,R_I1
10c STW R_I1,[[R_I0 + #16]]
110 SET NULL,R_I1 !ptr // comment: Setting the NULL value and returning to the loop
114 BPA B10 # 0x0c0
11c
11c B16: # N198 <- B14 B10 Loop: 0-21#0 IDom: 10/#8 Freq: 3.6e+00
11c RESTORE
120 RET ; NOP
128
128 B17: # B21 <- B1 Loop: 0-21#0 IDom: 1/#3 Freq: 1.0e-06
128 MOV R_O0,R_I0 !ptr
12c BPA B21 # 0x160
134
134 B18: # N198 <- B12 Loop: 0-21#0 IDom: 12/#10 Freq: 1.7e-05
134 MOV #-5,R_O0
138 CALL,static ; NOP ==> wrapper for: uncommon_trap
# TestVP::<init> @ bci:109 L0=R_I0 STK0=R_I1 STK1=R_I5
# R_I0=Oop R_I1=Oop
140 ILLTRAP ; ShouldNotReachHere
144
144 B19: # N198 <- B5 Loop: 0-21#0 IDom: 5/#7 Freq: 9.0e-06
144 MOV R_O0,R_I1 !ptr
148 MOV #-5,R_O0
14c CALL,static ; NOP ==> wrapper for: uncommon_trap
# TestVP::<init> @ bci:67 L0=R_I0 STK0=R_I1 STK1=R_L0
# R_I0=Oop R_I1=Oop
154 ILLTRAP ; ShouldNotReachHere
158
158 B20: # B21 <- B2 B6 B13 B11 Loop: 0-21#0 IDom: 2/#4 Freq: 4.4e-11
158 SET java/lang/NullPointerException:0xe9c37328 *,R_I0 !ptr
160
160 B21: # N198 <- B20 B17 Loop: 0-21#0 IDom: 1/#3 Freq: 1.0e-12
160 RESTORE
164 JMP rethrow_stub
170