RFR JDK-8011940 : java.lang.Class.getAnnotations() always enters synchronized method

Joel Borggrén-Franck joel.franck at oracle.com
Tue Aug 13 08:02:42 UTC 2013

Hi all,

Comments inline,

On 12 aug 2013, at 15:19, Paul Sandoz <paul.sandoz at oracle.com> wrote:
> On Aug 12, 2013, at 2:40 PM, Peter Levart <peter.levart at gmail.com> wrote:
>> On 08/12/2013 12:54 PM, Joel Borggren-Franck wrote:

>>> I realize the interaction between probably any reflective operation and
>>> a redefine is blurry, but if a redefine occurs between line 3308 and 3309
>>> annotationData() will return a possibly outdated AnnotationData.
>>> 3307             if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
>>> 3308                 // successfully installed new AnnotationData
>>> redefine here
>>> 3309                 return newAnnotationData;
>>> 3310             }
>>> I suppose there is a sequencing of events where this will be inevitable,
>>> but this got me thinking about the state model of annotations (and
>>> reflective objects) through an redefine.
>> The AnnotationData created and returned concurrently with class redefinition can contain old or new version, yes, but that's not a problem, since the AnnotationData also contains a "redefinedCount" field, so any further requests for annotations will trigger re-computation. This assumes that VM either changes the state returned by getRawAnnotations() and "classRedefinedCount" field atomically (during a safepoint?) or at least in order: 1st getRawAnnotations(), 2nd "classRedefinedCount". We 1st read "classRedefinedCount" and then
>> getRawAnnotations(), so there's no danger of keeping and returning stale data after redefinition.
>> This is more or less the same as with ReflectionData caching.
> I suppose one could do the cas without checking it's result:
> 3296     private AnnotationData annotationData() {
> 3297         while (true) { // retry loop
> 3298             AnnotationData annotationData = this.annotationData;
> 3299             int classRedefinedCount = this.classRedefinedCount;
> 3300             if (annotationData != null &&
> 3301                 annotationData.redefinedCount == classRedefinedCount) {
> 3302                 return annotationData;
> 3303             }
> 3304             // null or stale annotationData -> optimistically create new instance
> 3306             // try to install it
> 3307             Atomic.casAnnotationData(this, annotationData, createAnnotationData(classRedefinedCount));
>                 // re-check conditions in case a re-defintion occurred while creating
> 3311         }
> 3312     }
> Don't really know if it is worth it though, plus it might be better to break out the loop once set. Note frameworks, such as JAXB and JAX-RS will cache results of processing reflection and annotation information and need to be given a kick to re-process (e.g. like from JRebel).

I would guess it is not worth it. There still exists a sequencing of events such that the AnnotationData will be stale, the redefine just needs to happen after the return in this case. I suspect this is a fundamental issue with having reflective object that are not immutable. I think the fundamental problem here (which has nothing to do with Peters work) is that in general developers' mental model of core reflective objects is that they are immutable and suitable for caching. With class redefine that is not true and to make matters worse, we don't have a good story for "cache invalidation" of reflective objets. Again, this has nothing to do with Peters work.


More information about the core-libs-dev mailing list