[9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Vladimir Ivanov
vladimir.x.ivanov at oracle.com
Mon Dec 8 20:02:47 UTC 2014
Peter,
> First, just a nit. I think that in LambdaFormEditor:
>
> 289 private LambdaForm putInCache(Transform key, LambdaForm form) {
> 290 key = key.withResult(form);
> 291 for (int pass = 0; ; pass++) {
> 292 Object c = lambdaForm.transformCache;
> 293 if (c instanceof ConcurrentHashMap) {
> 294 @SuppressWarnings("unchecked")
> 295 ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
> 296 Transform k = m.putIfAbsent(key, key);
> 297 if (k == null) return form;
> 298 LambdaForm result = k.get();
> 299 if (result != null) {
> 300 return result;
> 301 } else {
> 302 if (m.replace(key, k, key)) {
> 303 return form;
> 304 } else {
> 305 continue;
> 306 }
> 307 }
> 308 }
> 309 assert(pass == 0);
> 310 synchronized (lambdaForm) {
> 311 c = lambdaForm.transformCache;
> 312 if (c instanceof ConcurrentHashMap)
> 313 continue;
>
> ...
>
> 372 lambdaForm.transformCache = c = m;
> ^^^ put assignment to 'c' back in
> 373 // The second iteration will update for this query, concurrently.
> 374 continue;
>
>
> ...you could move the assignment to 'c' in line 292 out of for loop and
> put it back in line 372, since once 'c' is instance of CHM,
> lambdaForm.transformCache never changes again and if 'c' is not CHM yet,
> it is re-assigned in lines 311 and 372 before next loop.
>
> Am I right?
Yes, it's correct. I decided to keep the code as-is to avoid
complicating the code even more - while working on the fix I traced c
usages at least twice :-)
> Now what scares me (might be that I don't have an intimacy with
> LambdaForm class like you do). There is a situation where you publish
> LambdaForm instances via data race.
>
> One form of LambdaForm.transformCache is an array of Transform objects
> (the other two forms are not problematic). Transform class has all
> fields final except the 'referent' field of SoftReference, which holds a
> LambdaForm instance. In the following line:
>
> 377 ta[idx] = key;
>
>
> ...you publish Transform object to an element of array with relaxed
> write, and in the following lines:
>
> 271 } else {
> 272 Transform[] ta = (Transform[])c;
> 273 for (int i = 0; i < ta.length; i++) {
> 274 Transform t = ta[i];
> 275 if (t == null) break;
> 276 if (t.equals(key)) { k = t; break; }
> 277 }
> 278 }
> 279 assert(k == null || key.equals(k));
> 280 return (k != null) ? k.get() : null;
>
>
> ...you obtain the element of the array with no synchronization and a
> relaxed read and might return a non-null referent (the LambdaForm) which
> is then returned as an interned instance.
>
> So can LambdaForm instances be published via data races without fear
> that they would appear half-initialized?
>
> That's what I didn't know when I used a lazySet coupled with volatile
> get to access array elements in my version:
>
> http://cr.openjdk.java.net/~plevart/misc/LambdaFormEditor.WeakCache/webrev.01/
As Paul already wrote, LambdaForms are safe to be published via a data
race, since it's structure is stored in final fields. LambdaForm cache
in MethodTypeForm is built on that property. For the reference, we had
discussed this aspect before (scattered in [1]).
Best regards,
Vladimir Ivanov
[1] http://mail.openjdk.java.net/pipermail/hotspot-dev/2014-May/013902.html
More information about the mlvm-dev
mailing list