Skip to content

Commit d4b2376

Browse files
author
duke
committed
Backport e13b4c8de944ab14a1d12f6251e83f4fdd9e0198
1 parent 4419ef2 commit d4b2376

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

src/java.base/share/classes/java/lang/ClassValue.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ synchronized <T> Object readAccess(ClassValue<T> classValue) {
476476
if (updated != entry) {
477477
put(classValue.identity, updated);
478478
}
479+
// Add to the cache, to enable the fast path, next time.
480+
checkCacheLoad();
481+
addToCache(classValue, updated);
479482
}
480483
return item;
481484
}

test/jdk/java/lang/invoke/ClassValueTest.java

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@
2323

2424
/*
2525
* @test
26-
* @bug 8351045 8351996
27-
* @enablePreview
28-
* @comment Remove preview if ScopedValue is finalized
26+
* @bug 8351045 8351996 8358535
2927
* @summary tests for class-specific values
28+
* @modules java.base/java.lang:+open
3029
* @library /test/lib
3130
* @run junit ClassValueTest
3231
*/
3332

3433
import java.lang.classfile.ClassFile;
3534
import java.lang.constant.ClassDesc;
35+
import java.lang.invoke.MethodHandle;
3636
import java.lang.invoke.MethodHandles;
37+
import java.lang.invoke.MethodType;
3738
import java.lang.ref.WeakReference;
3839
import java.time.Duration;
3940
import java.time.temporal.ChronoUnit;
4041
import java.util.ArrayList;
4142
import java.util.Arrays;
42-
import java.util.Iterator;
4343
import java.util.List;
4444
import java.util.concurrent.CountDownLatch;
4545
import java.util.concurrent.ThreadLocalRandom;
@@ -49,9 +49,7 @@
4949

5050
import jdk.test.lib.util.ForceGC;
5151
import org.junit.jupiter.api.Disabled;
52-
import org.junit.jupiter.api.RepeatedTest;
5352
import org.junit.jupiter.api.Test;
54-
import org.junit.jupiter.api.Timeout;
5553

5654
import static org.junit.jupiter.api.Assertions.*;
5755

@@ -479,4 +477,67 @@ protected Integer computeValue(Class<?> type) {
479477
awaitThreads(t);
480478
assertEquals(42, clv.get(int.class), "slow computation reinstalled value");
481479
}
480+
481+
// ClassValue cache invalidated and not reinstated when another
482+
// unrelated entry is removed
483+
@Test
484+
public void testCacheRefresh() throws Throwable {
485+
// Setup
486+
var lookup = MethodHandles.privateLookupIn(ClassValue.class, MethodHandles.lookup());
487+
var classValueEntryClass = Class.forName("java.lang.ClassValue$Entry");
488+
MethodHandle getCacheCarefully = lookup.findStatic(ClassValue.class, "getCacheCarefully",
489+
MethodType.methodType(classValueEntryClass.arrayType(), Class.class));
490+
var classValueMapClass = Class.forName("java.lang.ClassValue$ClassValueMap");
491+
MethodHandle probeHomeLocation = lookup.findStatic(classValueMapClass, "probeHomeLocation",
492+
MethodType.methodType(classValueEntryClass, classValueEntryClass.arrayType(), ClassValue.class));
493+
MethodHandle match = lookup.findVirtual(ClassValue.class, "match",
494+
MethodType.methodType(boolean.class, classValueEntryClass));
495+
496+
// Work
497+
ClassValue<?> clv = new ClassValue<>() {
498+
@Override
499+
protected String computeValue(Class<?> type) {
500+
return "";
501+
}
502+
};
503+
// A class that shouldn't have arbitrary values stuffing the cache
504+
var cleanClass = clv.getClass();
505+
clv.get(cleanClass); // create cache on clean class
506+
assertTrue(checkDirectCacheMatch(
507+
getCacheCarefully,
508+
probeHomeLocation,
509+
match,
510+
clv,
511+
cleanClass
512+
));
513+
clv.get(int.class);
514+
clv.remove(int.class); // invalidate cache on clean class
515+
assertFalse(checkDirectCacheMatch(
516+
getCacheCarefully,
517+
probeHomeLocation,
518+
match,
519+
clv,
520+
cleanClass
521+
));
522+
clv.get(cleanClass);
523+
assertTrue(checkDirectCacheMatch(
524+
getCacheCarefully,
525+
probeHomeLocation,
526+
match,
527+
clv,
528+
cleanClass
529+
));
530+
}
531+
532+
private static boolean checkDirectCacheMatch(
533+
MethodHandle getCacheCarefully,
534+
MethodHandle probeHomeLocation,
535+
MethodHandle match,
536+
ClassValue<?> clv,
537+
Class<?> cl
538+
) throws Throwable {
539+
Object cache = getCacheCarefully.invoke(cl);
540+
Object entry = probeHomeLocation.invoke(cache, clv);
541+
return (boolean) match.invoke(clv, entry);
542+
}
482543
}

0 commit comments

Comments
 (0)