-
Bug
-
Resolution: Fixed
-
P2
-
22
After JDK-8287061 the following assertion fails on big endian platforms (AIX, s390, Linux/PPC64be).
assert(0 <= i && i < _len) failed: illegal index at growableArray.hpp:145
Stack:
Stack: [0x00000fff6ac00000,0x00000fff6ae00000], sp=0x00000fff6adfc280, free space=2032k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0xde9a10] GrowableArrayView<ScopeValue*>::at(int)+0x84 (growableArray.hpp:145)
V [libjvm.so+0x109fbd0] ObjectMergeValue::select(frame&, RegisterMap&)+0x1dc (debugInfo.cpp:263)
V [libjvm.so+0x1b7e374] ScopeDesc::objects_to_rematerialize(frame&, RegisterMap&)+0x224 (scopeDesc.cpp:150)
V [libjvm.so+0x10d6694] rematerialize_objects(JavaThread*, int, CompiledMethod*, frame&, RegisterMap&, GrowableArray<compiledVFrame*>*, bool&)+0x1b8 (deoptimization.cpp:333)
V [libjvm.so+0x10d7924] Deoptimization::fetch_unroll_info_helper(JavaThread*, int)+0x56c (deoptimization.cpp:523)
V [libjvm.so+0x10dfb24] Deoptimization::uncommon_trap(JavaThread*, int, int)+0x64 (deoptimization.cpp:2572)
v ~UncommonTrapBlob 0x00000fff8beca2f4
J 1520 c2 vm.mlvm.meth.share.transform.v2.MHCall.check()V (97 bytes) @ 0x00000fff8c63ed58 [0x00000fff8c63e900+0x0000000000000458]
j vm.mlvm.meth.share.transform.v2.MHPrimitiveTF.computeInboundCall()Lvm/mlvm/meth/share/transform/v2/MHCall;+26
J 1392 c1 vm.mlvm.meth.share.transform.v2.MHMacroTF.addTransformation(Lvm/mlvm/meth/share/transform/v2/MHTF;)Lvm/mlvm/meth/share/transform/v2/MHCall; (95 bytes) @ 0x00000fff84bb96b4 [0x00000fff84bb9080+0x0000000000000634]
j vm.mlvm.meth.share.MHTransformationGen.createSequence(Lvm/mlvm/meth/share/Argument;Ljava/lang/Object;Ljava/lang/invoke/MethodHandle;[Lvm/mlvm/meth/share/Argument;)Lvm/mlvm/meth/share/transform/v2/MHMacroTF;+66
j vm.mlvm.meth.stress.compiler.sequences.Test.runThread(I)Z+34
The illegal index is always -559030609 (0xDEADDEAF)
vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java
vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java
are 2 tests that are prone to the assertion failure.
Analysis:
At https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/stackValue.cpp#L208-L213
the jint value is always put in the part with the lower address of the intptr_t value. On big endian platforms thats the location of the high word therefore the value cannot be cast directly back to jint.
Instead workarounds like these are needed:
https://github.com/openjdk/jdk/blob/8d29329138d44800ee4c0c02dacc01a06097de66/src/hotspot/share/runtime/deoptimization.cpp#L1358-L1391
https://github.com/openjdk/jdk/blob/8d29329138d44800ee4c0c02dacc01a06097de66/src/hotspot/share/runtime/deoptimization.cpp#L1489-L1519
I wonder if this is needed at all or if we could just do this instead:
return UCONST64(0xDEADDEAF00000000) | *(juint*)value_addr
EDIT: yes it is indeed needed but only on big endian. The size of a stack slot is sizeof(intptr_t). On big endian it depends on the type of an integer value where in the slot it is stored (at lower or higher address). Therefore reading the complete intptr_t and then casting it to jint does not work.
Details:
- Let intptr_t* S be the address of a stack slot
- When accessing S, interpreter and compiled code use load/store instructions matching the size of the integer value to be transferred.
- E.g. to access a jint in S, 32bit load/store instructions are used. Thats very much like casting S to jint*
- (jint)*(intptr_t*)S does not work on big endian because the jint part is in the high word of *(intptr_t*)S
- StackValue has to mimic this to be able to transfer the complete intptr_t value. E.g. `interpretedVFrame::set_locals`[1] transfers stack slot values without knowing if the value is a jint or jlong.
[1] https://github.com/openjdk/jdk/blob/842d6329cf5a3da8df7eddb195b5fcb7baadbdc3/src/hotspot/share/runtime/vframe.cpp#L456
assert(0 <= i && i < _len) failed: illegal index at growableArray.hpp:145
Stack:
Stack: [0x00000fff6ac00000,0x00000fff6ae00000], sp=0x00000fff6adfc280, free space=2032k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0xde9a10] GrowableArrayView<ScopeValue*>::at(int)+0x84 (growableArray.hpp:145)
V [libjvm.so+0x109fbd0] ObjectMergeValue::select(frame&, RegisterMap&)+0x1dc (debugInfo.cpp:263)
V [libjvm.so+0x1b7e374] ScopeDesc::objects_to_rematerialize(frame&, RegisterMap&)+0x224 (scopeDesc.cpp:150)
V [libjvm.so+0x10d6694] rematerialize_objects(JavaThread*, int, CompiledMethod*, frame&, RegisterMap&, GrowableArray<compiledVFrame*>*, bool&)+0x1b8 (deoptimization.cpp:333)
V [libjvm.so+0x10d7924] Deoptimization::fetch_unroll_info_helper(JavaThread*, int)+0x56c (deoptimization.cpp:523)
V [libjvm.so+0x10dfb24] Deoptimization::uncommon_trap(JavaThread*, int, int)+0x64 (deoptimization.cpp:2572)
v ~UncommonTrapBlob 0x00000fff8beca2f4
J 1520 c2 vm.mlvm.meth.share.transform.v2.MHCall.check()V (97 bytes) @ 0x00000fff8c63ed58 [0x00000fff8c63e900+0x0000000000000458]
j vm.mlvm.meth.share.transform.v2.MHPrimitiveTF.computeInboundCall()Lvm/mlvm/meth/share/transform/v2/MHCall;+26
J 1392 c1 vm.mlvm.meth.share.transform.v2.MHMacroTF.addTransformation(Lvm/mlvm/meth/share/transform/v2/MHTF;)Lvm/mlvm/meth/share/transform/v2/MHCall; (95 bytes) @ 0x00000fff84bb96b4 [0x00000fff84bb9080+0x0000000000000634]
j vm.mlvm.meth.share.MHTransformationGen.createSequence(Lvm/mlvm/meth/share/Argument;Ljava/lang/Object;Ljava/lang/invoke/MethodHandle;[Lvm/mlvm/meth/share/Argument;)Lvm/mlvm/meth/share/transform/v2/MHMacroTF;+66
j vm.mlvm.meth.stress.compiler.sequences.Test.runThread(I)Z+34
The illegal index is always -559030609 (0xDEADDEAF)
vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java
vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java
are 2 tests that are prone to the assertion failure.
Analysis:
At https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/stackValue.cpp#L208-L213
the jint value is always put in the part with the lower address of the intptr_t value. On big endian platforms thats the location of the high word therefore the value cannot be cast directly back to jint.
Instead workarounds like these are needed:
https://github.com/openjdk/jdk/blob/8d29329138d44800ee4c0c02dacc01a06097de66/src/hotspot/share/runtime/deoptimization.cpp#L1358-L1391
https://github.com/openjdk/jdk/blob/8d29329138d44800ee4c0c02dacc01a06097de66/src/hotspot/share/runtime/deoptimization.cpp#L1489-L1519
I wonder if this is needed at all or if we could just do this instead:
return UCONST64(0xDEADDEAF00000000) | *(juint*)value_addr
EDIT: yes it is indeed needed but only on big endian. The size of a stack slot is sizeof(intptr_t). On big endian it depends on the type of an integer value where in the slot it is stored (at lower or higher address). Therefore reading the complete intptr_t and then casting it to jint does not work.
Details:
- Let intptr_t* S be the address of a stack slot
- When accessing S, interpreter and compiled code use load/store instructions matching the size of the integer value to be transferred.
- E.g. to access a jint in S, 32bit load/store instructions are used. Thats very much like casting S to jint*
- (jint)*(intptr_t*)S does not work on big endian because the jint part is in the high word of *(intptr_t*)S
- StackValue has to mimic this to be able to transfer the complete intptr_t value. E.g. `interpretedVFrame::set_locals`[1] transfers stack slot values without knowing if the value is a jint or jlong.
[1] https://github.com/openjdk/jdk/blob/842d6329cf5a3da8df7eddb195b5fcb7baadbdc3/src/hotspot/share/runtime/vframe.cpp#L456
- relates to
-
JDK-8312753 Assimilate Deoptimization::reassign_type_array_elements and reassign_fields_by_klass
- Open
-
JDK-8287061 Support for rematerializing scalar replaced objects participating in allocation merges
- Resolved