On Thu, 16 May 2024 09:01:22 GMT, Per Minborg <pminb...@openjdk.org> wrote:
>> # Stable Values & Collections (Internal) >> >> ## Summary >> This PR proposes to introduce an internal _Stable Values & Collections_ API, >> which provides immutable value holders where elements are initialized _at >> most once_. Stable Values & Collections offer the performance and safety >> benefits of final fields while offering greater flexibility as to the timing >> of initialization. >> >> ## Goals >> * Provide an easy and intuitive API to describe value holders that can >> change at most once. >> * Decouple declaration from initialization without significant footprint or >> performance penalties. >> * Reduce the amount of static initializer and/or field initialization code. >> * Uphold integrity and consistency, even in a multi-threaded environment. >> >> For more details, see the draft JEP: https://openjdk.org/jeps/8312611 >> >> ## Performance >> Performance compared to instance variables using two `AtomicReference` and >> two protected by double-checked locking under concurrent access by all >> threads: >> >> >> Benchmark Mode Cnt Score >> Error Units >> StableBenchmark.atomic thrpt 10 259.478 ? >> 36.809 ops/us >> StableBenchmark.dcl thrpt 10 225.710 ? >> 26.638 ops/us >> StableBenchmark.stable thrpt 10 4382.478 ? >> 1151.472 ops/us <- StableValue significantly faster >> >> >> Performance compared to static variables protected by `AtomicReference`, >> class-holder idiom holder, and double-checked locking (all threads): >> >> >> Benchmark Mode Cnt Score >> Error Units >> StableStaticBenchmark.atomic thrpt 10 6487.835 ? >> 385.639 ops/us >> StableStaticBenchmark.dcl thrpt 10 6605.239 ? >> 210.610 ops/us >> StableStaticBenchmark.stable thrpt 10 14338.239 ? >> 1426.874 ops/us >> StableStaticBenchmark.staticCHI thrpt 10 13780.341 ? >> 1839.651 ops/us >> >> >> Performance for stable lists (thread safe) in both instance and static >> contexts whereby we access a single value compared to `ArrayList` instances >> (which are not thread-safe) (all threads): >> >> >> Benchmark Mode Cnt Score >> Error Units >> StableListElementBenchmark.instanceArrayList thrpt 10 5812.992 ? >> 1169.730 ops/us >> StableListElementBenchmark.instanceList thrpt 10 4818.643 ? >> 704.893 ops/us >> StableListElementBenchmark... > > Per Minborg has updated the pull request incrementally with one additional > commit since the last revision: > > Use byte for storing state and compute flags src/java.base/share/classes/jdk/internal/lang/stable/StableAccess.java line 63: > 61: Function<? super T, ? > extends R> original) { > 62: return new MemoizedFunction<>(stableMap, original); > 63: } Maybe also rename these? Suggestion: public static <T> Supplier<T> memoizedSupplier(StableValue<T> stable, Supplier<? extends T> original) { return new MemoizedSupplier<>(stable, original); } public static <R> IntFunction<R> memoizedIntFunction(List<StableValue<R>> stableList, IntFunction<? extends R> original) { return new MemoizedIntFunction<>(stableList, original); } public static <T, R> Function<T, R> memoizedFunction(Map<T, StableValue<R>> stableMap, Function<? super T, ? extends R> original) { return new MemoizedFunction<>(stableMap, original); } src/jdk.unsupported/share/classes/sun/misc/Unsafe.java line 729: > 727: } > 728: } > 729: } Given that the [`Class::forName(String, boolean, ClassLoader)`] method doesn’t care about whether the requested class is actually exported to the caller, it’s possible to do the following: Suggestion: final class Holder { static final Class<?> TRUSTED_FIELD_TYPE; static { PrivilegedAction<ClassLoader> getPlatformClassLoader = ClassLoader::getPlatformClassLoader; @SuppressWarnings("removal") ClassLoader platformClassLoader = AccessController.doPrivileged(getPlatformClassLoader); try { TRUSTED_FIELD_TYPE = Class.forName("jdk.internal.lang.stable.TrustedFieldType", false, platformClassLoader); } catch (ClassNotFoundException e) { throw new AssertionError(e); } } } Class<?> declaringClass = f.getDeclaringClass(); if (declaringClass.isHidden()) { throw new UnsupportedOperationException("can't get base address on a hidden class: " + f); } if (declaringClass.isRecord()) { throw new UnsupportedOperationException("can't get base address on a record class: " + f); } Class<?> fieldType = f.getType(); if (Holder.TRUSTED_FIELD_TYPE.isAssignableFrom(fieldType)) { throw new UnsupportedOperationException("can't get field offset for a field of type " + fieldType.getName() + ": " + f); } [`Class::forName(String, boolean, ClassLoader)`]: https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/Class.html#forName(java.lang.String,boolean,java.lang.ClassLoader) ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1603032451 PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1603089512