I have a test case where it appears that compiler2 is getting
confused about the type of an array, and optimizing an array store
such that it always goes to an uncommon trap, instead of always
succeeding (or at least always generating both fast path and slow
path code). [ The test case is in the "Attachments..." section. ]
At the current time I think this is just a performance degradation
for Ladybird users. However, the Java source code patterns involved
can be heavily used in some Corba ORB methods. I will have to figure
out something for the Gemstone/Brokat VM (with object persistence
modifications) since the parse graph produced by this bug is upsetting
my parsing changes for array write barriers.
I re-ran the test on unmodified sources from
hotspot-1_3_1-pre-fcs-src-b22-solsparc-17_apr_2001.zip using a fastdebug
buildThe fastdebug libjvm.so was installed into a binary jre from 1.3.1 b19.
The command line to reproduce the problem is
java -server -XX:-BackgroundCompilation testior
The attached zip file contains
.hotspot_compiler - have in current directory to print the interesting methods
fakeIOR.java - the class with a method that gets bad code generated
fakeIOR.class
testior.java - main proram for the test
testior.class
hotspot.log - output from a run that shows the generated code using
the hotspot-1_3_1-pre-fcs-src-b22 sources.
bug.txt - my current analysis of the problem
------------------------------------------------------------------------------
Here is some further diagnosis (line numbers may not match your
source line numbers)
At this stack, a ciTypeArrayKlass is created for the LoadKlassNode
for the array_store_check that gets the fast_path turned into _top
-----------------------
[1] ciTypeArrayKlass::make(t = T_INT), line 56 in "ciTypeArrayKlass.cpp"
=>[2] TypeAryPtr::klass(this = 0x23b3a0), line 2470 in "type.cpp"
[3] TypeAryPtr::klass(this = 0x23daac), line 2461 in "type.cpp"
[4] LoadKlassNode::Value(this = 0x346320, phase = 0xefb814f8), line 398 in "memnode.cpp"
[5] PhaseGVN::transform(this = 0xefb814f8, n = 0x346320), line 582 in "phaseX.cpp"
[6] Parse::array_store_check(this = 0xefb813e0, bci = 19), line 475 in "parseHelper.cpp"
[7] Parse::do_one_bytecode(this = 0xefb813e0, bc = _aastore, iter = CLASS, cloning = 0), line 1003 in "parse2.cpp"
now more detail on some of the frames:
[1] ciTypeArrayKlass::make(t = T_INT), line 56 in "ciTypeArrayKlass.cpp"
[2] TypeAryPtr::klass(this = 0x23b3a0), line 2470 in "type.cpp"
2469 // Compute array klass directly from basic type
2470 k_ary = ciTypeArrayKlass::make(Type::_basic_type[_ary->_elem->_base]);
(dbx) p this->dump()
byte[int+]*
(dbx) p _ary->dump()
byte[int+]
(dbx) p _ary->_elem->dump()
byte
(dbx) p _ary->_elem->_base
_ary->_elem->_base = Int
(dbx) p (int)_ary->_elem->_base
(int ) _ary->_elem->_base = 3
[3] TypeAryPtr::klass(this = 0x23daac), line 2461 in "type.cpp"
2460 // Compute array klass from element klass
2461 ciKlass *cik = tary->klass();
(dbx) p this->dump()
byte[int+]*[int+]:NotNull*+4this->dump() = (void)
[4] LoadKlassNode::Value(this = 0x346320, phase = 0xefb814f8), line 398 in "memnode.cpp"
396 const TypeAryPtr *tary = tp->isa_aryptr();
397 if( tary != NULL ) {
398 ciKlass *tary_klass = tary->klass(); <<<< HERE
[5] PhaseGVN::transform(this = 0xefb814f8, n = 0x346320), line 582 in "phaseX.cpp"
[6] Parse::array_store_check(this = 0xefb813e0, bci = 19), line 475 in "parseHelper.cpp"
475 Node* array_klass = _gvn.transform(new (3) LoadKlassNode(0, memory(TypeOopPtr::HEADER), p, TypeKlassPtr::OBJECT));
[7] Parse::do_one_bytecode(this = 0xefb813e0, bc = _aastore, iter = CLASS, cloning = 0), line 1003 in "parse2.cpp"
------------------
Then set a breakpoint at memnode.cpp:399
398 ciKlass *tary_klass = tary->klass(); << ABOVE STACK WAS HERE
399 if( tary_klass != NULL ) { // can be NULL when at BOTTOM or TOP <<< STOP HERE
And run to the breakpoint, which yields this stack
=>[1] LoadKlassNode::Value(this = 0x346320, phase = 0xefb814f8), line 399 in "memnode.cpp"
[2] PhaseGVN::transform(this = 0xefb814f8, n = 0x346320), line 582 in "phaseX.cpp"
[3] Parse::array_store_check(this = 0xefb813e0, bci = 19), line 475 in "parseHelper.cpp"
(dbx) f 1
Current function is LoadKlassNode::Value
399 if( tary_klass != NULL ) { // can be NULL when at BOTTOM or TOP
examination shows
*tary_klass = {
ciKlass::ciObject::_handle = 0x217220
ciKlass::ciObject::_klass = (nil)
ciKlass::_name = 0x349e48
}
(dbx) x 0x217220 / 1 X
0x00217220: 0xf6d50f18
then printing the oop 0xf6d50f18 :
At 0xf6d50f18 , size 74 : {object array class}
mark(hash 0,age 0)
- klass: {other class} (0xf6c00100)
- instance klass: {type array int} <<<< WRONG, I think, should be {type array byte}
---------------
Later on the bad ciKlass is used to optimize the type compare in array_store_check,
and comparing {type array int} from the ciClass of the value being stored to
{type array byte} from the type of the destination of the aastore always yields false.
So I think there is a confusion in the type system between ciClass and opto/type.cpp
confused about the type of an array, and optimizing an array store
such that it always goes to an uncommon trap, instead of always
succeeding (or at least always generating both fast path and slow
path code). [ The test case is in the "Attachments..." section. ]
At the current time I think this is just a performance degradation
for Ladybird users. However, the Java source code patterns involved
can be heavily used in some Corba ORB methods. I will have to figure
out something for the Gemstone/Brokat VM (with object persistence
modifications) since the parse graph produced by this bug is upsetting
my parsing changes for array write barriers.
I re-ran the test on unmodified sources from
hotspot-1_3_1-pre-fcs-src-b22-solsparc-17_apr_2001.zip using a fastdebug
buildThe fastdebug libjvm.so was installed into a binary jre from 1.3.1 b19.
The command line to reproduce the problem is
java -server -XX:-BackgroundCompilation testior
The attached zip file contains
.hotspot_compiler - have in current directory to print the interesting methods
fakeIOR.java - the class with a method that gets bad code generated
fakeIOR.class
testior.java - main proram for the test
testior.class
hotspot.log - output from a run that shows the generated code using
the hotspot-1_3_1-pre-fcs-src-b22 sources.
bug.txt - my current analysis of the problem
------------------------------------------------------------------------------
Here is some further diagnosis (line numbers may not match your
source line numbers)
At this stack, a ciTypeArrayKlass is created for the LoadKlassNode
for the array_store_check that gets the fast_path turned into _top
-----------------------
[1] ciTypeArrayKlass::make(t = T_INT), line 56 in "ciTypeArrayKlass.cpp"
=>[2] TypeAryPtr::klass(this = 0x23b3a0), line 2470 in "type.cpp"
[3] TypeAryPtr::klass(this = 0x23daac), line 2461 in "type.cpp"
[4] LoadKlassNode::Value(this = 0x346320, phase = 0xefb814f8), line 398 in "memnode.cpp"
[5] PhaseGVN::transform(this = 0xefb814f8, n = 0x346320), line 582 in "phaseX.cpp"
[6] Parse::array_store_check(this = 0xefb813e0, bci = 19), line 475 in "parseHelper.cpp"
[7] Parse::do_one_bytecode(this = 0xefb813e0, bc = _aastore, iter = CLASS, cloning = 0), line 1003 in "parse2.cpp"
now more detail on some of the frames:
[1] ciTypeArrayKlass::make(t = T_INT), line 56 in "ciTypeArrayKlass.cpp"
[2] TypeAryPtr::klass(this = 0x23b3a0), line 2470 in "type.cpp"
2469 // Compute array klass directly from basic type
2470 k_ary = ciTypeArrayKlass::make(Type::_basic_type[_ary->_elem->_base]);
(dbx) p this->dump()
byte[int+]*
(dbx) p _ary->dump()
byte[int+]
(dbx) p _ary->_elem->dump()
byte
(dbx) p _ary->_elem->_base
_ary->_elem->_base = Int
(dbx) p (int)_ary->_elem->_base
(int ) _ary->_elem->_base = 3
[3] TypeAryPtr::klass(this = 0x23daac), line 2461 in "type.cpp"
2460 // Compute array klass from element klass
2461 ciKlass *cik = tary->klass();
(dbx) p this->dump()
byte[int+]*[int+]:NotNull*+4this->dump() = (void)
[4] LoadKlassNode::Value(this = 0x346320, phase = 0xefb814f8), line 398 in "memnode.cpp"
396 const TypeAryPtr *tary = tp->isa_aryptr();
397 if( tary != NULL ) {
398 ciKlass *tary_klass = tary->klass(); <<<< HERE
[5] PhaseGVN::transform(this = 0xefb814f8, n = 0x346320), line 582 in "phaseX.cpp"
[6] Parse::array_store_check(this = 0xefb813e0, bci = 19), line 475 in "parseHelper.cpp"
475 Node* array_klass = _gvn.transform(new (3) LoadKlassNode(0, memory(TypeOopPtr::HEADER), p, TypeKlassPtr::OBJECT));
[7] Parse::do_one_bytecode(this = 0xefb813e0, bc = _aastore, iter = CLASS, cloning = 0), line 1003 in "parse2.cpp"
------------------
Then set a breakpoint at memnode.cpp:399
398 ciKlass *tary_klass = tary->klass(); << ABOVE STACK WAS HERE
399 if( tary_klass != NULL ) { // can be NULL when at BOTTOM or TOP <<< STOP HERE
And run to the breakpoint, which yields this stack
=>[1] LoadKlassNode::Value(this = 0x346320, phase = 0xefb814f8), line 399 in "memnode.cpp"
[2] PhaseGVN::transform(this = 0xefb814f8, n = 0x346320), line 582 in "phaseX.cpp"
[3] Parse::array_store_check(this = 0xefb813e0, bci = 19), line 475 in "parseHelper.cpp"
(dbx) f 1
Current function is LoadKlassNode::Value
399 if( tary_klass != NULL ) { // can be NULL when at BOTTOM or TOP
examination shows
*tary_klass = {
ciKlass::ciObject::_handle = 0x217220
ciKlass::ciObject::_klass = (nil)
ciKlass::_name = 0x349e48
}
(dbx) x 0x217220 / 1 X
0x00217220: 0xf6d50f18
then printing the oop 0xf6d50f18 :
At 0xf6d50f18 , size 74 : {object array class}
mark(hash 0,age 0)
- klass: {other class} (0xf6c00100)
- instance klass: {type array int} <<<< WRONG, I think, should be {type array byte}
---------------
Later on the bad ciKlass is used to optimize the type compare in array_store_check,
and comparing {type array int} from the ciClass of the value being stored to
{type array byte} from the type of the destination of the aastore always yields false.
So I think there is a confusion in the type system between ciClass and opto/type.cpp