RFR: 8278065: Refactor subclassAudits to use ClassValue [v3]
Roman Kennke
rkennke at openjdk.java.net
Mon Jan 10 20:46:40 UTC 2022
On Fri, 10 Dec 2021 21:07:37 GMT, Roman Kennke <rkennke at openjdk.org> wrote:
>> As a follow-up to #6375, this change refactors java.io.ObjectInputStream.Caches#subclassAudits and java.io.ObjectOutputStream.Caches#subclassAudits to use ClassValue instead of SoftReference, similar to what we did in #6375 for java.io.ObjectStreamClass.Caches#localDescs. Then we can now also remove the common machinery java.io.ObjectStreamClass#processQueue and java.io.ObjectStreamClass.WeakClassKey.
>>
>> Testing:
>> - [x] tier1
>> - [x] tier2
>> - [ ] tier3
>
> Roman Kennke has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains ten commits:
>
> - Merge branch 'master' into JDK-8278065
> - 8278065: Refactor subclassAudits to use ClassValue
> - Remove unused EntryFuture inner class from ObjectSteamClass
> - Merge remote-tracking branch 'jdk-plevart/JDK-8277072-peter' into JDK-8277072
> - Use ClassValue to solve JDK-8277072
> - Use ForceGC instead of System.gc()
> - Convert test to testng
> - Fix indentation of new testcase
> - 8277072: ObjectStreamClass caches keep ClassLoaders alive
I think we shoul
> ...well I tried to do that. And it is not so simple. Here's what I came up with:
>
> ```java
> public final class ClassFlags {
>
> private static final class AtomicByte {
> private static final VarHandle VALUE;
>
> static {
> try {
> VALUE = MethodHandles.lookup().findVarHandle(AtomicByte.class, "value", byte.class);
> } catch (NoSuchFieldException | IllegalAccessException e) {
> throw new InternalError(e);
> }
> }
>
> private volatile byte value;
>
> byte get() {
> return value;
> }
>
> byte compareAndExchange(byte expectedValue, byte newValue) {
> return (byte) VALUE.compareAndExchange(this, (byte) expectedValue, (byte) newValue);
> }
> }
>
> private final Predicate<? super Class<?>>[] typePredicates;
> private final ClassValue<AtomicByte> flagsCV = new ClassValue<>() {
> @Override
> protected AtomicByte computeValue(Class<?> type) {
> return new AtomicByte();
> }
> };
>
> @SafeVarargs
> public ClassFlags(Predicate<? super Class<?>>... typePredicates) {
> if (typePredicates.length > 4) {
> throw new IllegalArgumentException("Up to 4 flags are supported in a single ClassFlags instance");
> }
> this.typePredicates = typePredicates;
> }
>
> public boolean get(Class<?> type, int index) {
> Objects.checkIndex(index, typePredicates.length);
>
> AtomicByte flags = flagsCV.get(type);
> int f = flags.get() & 0xFF;
> int falseMask = 0x1 << (index + index);
> int trueMask = falseMask << 1;
> int mask = falseMask | trueMask;
> int value = 0;
> while ((f & mask) == 0) {
> if (value == 0) {
> value = typePredicates[index].test(type) ? trueMask : falseMask;
> }
> int fn = (f & ~mask) | value;
> int fv = flags.compareAndExchange((byte) f, (byte) fn) & 0xFF;
> if (fv == f) {
> f = fn;
> break;
> } else {
> f = fv;
> }
> }
> return (f & trueMask) != 0;
> }
> }
> ```
>
> So I don't know if it's worth it... Simplicity of your implementation probably out-weights the footprint savings of above code.
>
> Regards, Peter
I think I'd rather keep it simple. Can you please give it a review, too? Thanks, Roman
-------------
PR: https://git.openjdk.java.net/jdk/pull/6637
More information about the core-libs-dev
mailing list