JDK-7024561 : JSR 292 constant pool cache _f1 field doesn't get properly updated with parallel GC
Type:Bug
Component:hotspot
Sub-Component:compiler
Affected Version:hs21
Priority:P3
Status:Closed
Resolution:Duplicate
OS:generic
CPU:generic
Submitted:2011-03-04
Updated:2011-04-07
Resolved:2011-04-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.
A testcase Remi Forax posted on mlvm-dev:
http://mail.openjdk.java.net/pipermail/mlvm-dev/2011-March/002555.html
shows a problem with JSR 292 and parallel GC.
Comments
EVALUATION
Fixed as part of this bug, which had a similar requirement to scavenge the constant pool cache:
7017732: move static fields into Class to prepare for perm gen removal
07-04-2011
SUGGESTED FIX
diff --git a/src/share/vm/oops/cpCacheKlass.cpp b/src/share/vm/oops/cpCacheKlass.cpp
--- a/src/share/vm/oops/cpCacheKlass.cpp
+++ b/src/share/vm/oops/cpCacheKlass.cpp
@@ -173,11 +173,11 @@
// during a scavenge, it is safe to inspect my pool, since it is perm
constantPoolOop pool = cache->constant_pool();
assert(pool->is_constantPool(), "should be constant pool");
- if (pool->has_invokedynamic()) {
+ if (true) {
for (int i = 0; i < cache->length(); i++) {
ConstantPoolCacheEntry* e = cache->entry_at(i);
oop* p = (oop*)&e->_f1;
- if (e->is_secondary_entry()) {
+ if (true) {
if (PSScavenge::should_scavenge(p))
pm->claim_or_forward_depth(p);
assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)),
Also, remove the has_invokedynamic and set_invokedynamic methods, if this is the sole use of them outside of printing code.
30-03-2011
EVALUATION
This is bug-tail from 6984311. The problem experienced by the customer appears to be with CONSTANT_MethodHandle entries representing BSMs.
The routine constantPoolOopDesc::resolve_constant_at_impl call set_f1 to store a resolved constant into a CP cache. The constant oops stored there will, in general, fail to be scavenged.
Before 6984311, the only scavengeable oops stored in _f1 were CallSite pointers put there by ConstantPoolCacheEntry::set_dynamic_call. In that particular case, the gating in constantPoolCacheKlass::oop_push_contents would allow all such CallSite pointers to be scavenged as necessary. The gating is on (a) the presence of resolved invokedynamic instructions, and (b) on the _f1 being in a "secondary" (CallSite) CP cache entry.
After 6984311, other scavengeable oops are stored in various _f1 entries.
Therefore, the fix to this bug is to remove the guards in constantPoolCacheKlass::oop_push_contents. See Suggested Fix.
30-03-2011
EVALUATION
This works with UseSerialGC but fails with UseParallelGC.
$ gamma -XX:+UseParallelGC -XX:+TraceMethodHandles -XX:+PrintGC -XX:+PrintMiscellaneous -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic -cp . Megamorphic2
...
resolving bootstrap method for 0xb65daf98 at 2 at cache[18]CP[143]...
result_oop: e4e51720
sun.dyn.DirectMethodHandle
- klass: 'sun/dyn/DirectMethodHandle'
- ---- fields (total size 6 words):
- private 'vmentry' 'I' @8 -93565868 (fa6c4c54)
- protected 'vmtarget' 'Ljava/lang/Object;' @12 {method} 'staticBootstrap' '(Ljava/dyn/MethodHandles$Lookup;Ljava/lang/String;Ljava/dyn/MethodType;[Ljava/lang/Object;)Ljava/dyn/CallSite;' in 'jsr335/lambda/optimizer/RT' (b65f2738)
- private 'type' 'Ljava/dyn/MethodType;' @16 a 'java/dyn/MethodType' = (Ljava/dyn/MethodHandles$Lookup;Ljava/lang/String;Ljava/dyn/MethodType;[Ljava/lang/Object;)Ljava/dyn/CallSite; (e4e50f00)
- private final 'vmindex' 'I' @20 -2 (fffffffe)
bootstrap method for 0xb65daf98 at 2 retrieved as 0xe4e51720:
...
[GC 16896K->5180K(62720K), 0.1407775 secs]
[GC 22076K->6300K(79616K), 0.1852707 secs]
[GC 40092K->8564K(81152K), 0.5988057 secs]
[GC 43892K->11040K(113920K), 0.7261760 secs]
[GC 79136K->15784K(113920K), 1.1371119 secs]
[GC 83880K->20608K(188224K), 1.0771812 secs]
resolving bootstrap method for 0xb65daf98 at 9 at cache[18]CP[143]...
result_oop: e4e51720
[Ljava.lang.Object;
- klass: 'java/lang/Object'[]
- length: 1
- 0 : "foo"
bootstrap method for 0xb65daf98 at 9 retrieved as 0xe4e51720:
Exception in thread "main" java.lang.IllegalStateException: no bootstrap method found for invokedynamic
at Megamorphic2.test(Megamorphic2.java:60)
at Megamorphic2.main(Megamorphic2.java:52)
The first time result_oop points to the correct BSM but later, after a couple of GC cycles, the pointer value is still the same but the Java heap object behind it has changed. It's purely random if there is a valid object or it points to some other memory, which may result in an assert:
# Internal Error (/home/twisti/hotspot-comp/hotspot/src/share/vm/classfile/systemDictionary.cpp:2585), pid=10916, tid=2
# assert(bsm_oop->is_oop()) failed: must be sane