11package jdk .internal .access ;
22
3- import jdk .internal .misc .Unsafe ;
4- import jdk .internal .vm .annotation .ForceInline ;
5- import jdk .internal .vm .annotation .Stable ;
6-
73import java .util .Objects ;
84import java .util .Set ;
9- import java .util .StringJoiner ;
105
116// This class is required to be able to be used very early in the boot sequence.
127// Because of this, it does not use reflection, MethodHandles, or ImmutableCollections
1510 * <p>
1611 * The lookup of components can be eligible for constant folding if the stable component
1712 * container is a VM constant (e.g., is declared as a `static final` field) and the
18- * lookup key is a constant (e.g., a class literal)..
13+ * lookup key is a constant (e.g., a class literal).
14+ * <p>
15+ * Except if otherwise specified, all methods throw a {@linkplain NullPointerException}
16+ * if a {@code null} parameter is provided.
1917 *
2018 * @param <T> The common type of the components. The type can be {@linkplain Object} if
2119 * there is no common super type for the components.
2220 */
23- public sealed interface StableComponentContainer <T > {
21+ public sealed interface StableComponentContainer <T > permits StableComponentContainerImpl {
2422
2523 /**
2624 * {@return the associated component for the provided {@code type}}
2725 *
2826 * @param type to use as lookup
2927 * @param <C> component type
3028 * @throws IllegalArgumentException if the provided {@code type} was not specified
31- * at construction.
29+ * {@linkplain StableComponentContainer#of(Set) at construction} .
3230 */
3331 <C extends T > C get (Class <C > type );
3432
@@ -41,7 +39,7 @@ public sealed interface StableComponentContainer<T> {
4139 * (nullable)
4240 * @param <C> component type
4341 * @throws IllegalArgumentException if the provided {@code type} was not specified
44- * at construction.
42+ * {@linkplain StableComponentContainer#of(Set) at construction} .
4543 */
4644 <C extends T > C orElse (Class <C > type , C other );
4745
@@ -51,118 +49,29 @@ public sealed interface StableComponentContainer<T> {
5149 *
5250 * @param type to use as lookup
5351 * @throws IllegalArgumentException if the provided {@code type} was not specified
54- * at construction.
52+ * {@linkplain StableComponentContainer#of(Set) at construction} .
5553 */
5654 boolean isInitialized (Class <? extends T > type );
5755
5856 /**
5957 * Associates the provided {@code type} with the provided {@code component}
6058 *
6159 * @param type to use as lookup
60+ * @throws IllegalArgumentException if the provided {@code type} was not specified
61+ * {@linkplain StableComponentContainer#of(Set) at construction}.
6262 * @throws IllegalStateException if the provided {@code type} was already associated
6363 * with a component
6464 */
6565 <C extends T > void set (Class <C > type , C component );
6666
67- record StableComponentContainerImpl <T >(@ Stable Object [] table ) implements StableComponentContainer <T > {
68-
69- private static final Unsafe UNSAFE = Unsafe .getUnsafe ();
70-
71- @ ForceInline
72- public <C extends T > C get (Class <C > type ) {
73- return type .cast (componentRaw (type ));
74- }
75-
76- public boolean isInitialized (Class <? extends T > type ) {
77- return componentRaw (type ) != null ;
78- }
79-
80- @ Override
81- public <C extends T > C orElse (Class <C > type , C other ) {
82- final Object componentRaw = componentRaw (type );
83- return componentRaw == null ? other : type .cast (componentRaw );
84- }
85-
86- @ ForceInline
87- private Object componentRaw (Class <?> type ) {
88- Objects .requireNonNull (type );
89- final int probe = probeOrThrow (type );
90- return UNSAFE .getReferenceAcquire (table , nextOffset (offsetFor (probe )));
91- }
92-
93- public <C extends T > void set (Class <C > type , C component ) {
94- // Implicit null check of both `type` and `component`
95- if (!type .isInstance (component )) {
96- throw new IllegalArgumentException ();
97- }
98- final int probe = probeOrThrow (type );
99- if (!UNSAFE .compareAndSetReference (table , nextOffset (offsetFor (probe )), null , component )) {
100- throw new IllegalStateException ("The component is already initialized: " + type .getName ());
101- }
102- }
103-
104- @ Override
105- public String toString () {
106- return "StableComponentContainer" + associations (true );
107- }
108-
109- private String associations (boolean showValues ) {
110- final StringJoiner sj = new StringJoiner (", " );
111- for (int i = 0 ; i < table .length ; i +=2 ) {
112- final Class <?> type = (Class <?>) table [i ];
113- if (type != null ) {
114- if (showValues ) {
115- final Object component = UNSAFE .getReferenceAcquire (table , nextOffset (offsetFor (i )));
116- sj .add (type .getName () + (component != null ? "=" + component : "" ));
117- } else {
118- sj .add (type .toString ());
119- }
120- }
121- }
122- return "{" + sj + "}" ;
123- }
124-
125- @ ForceInline
126- private int probeOrThrow (Class <?> type ) {
127- final int probe = probe (table , type );
128- if (probe < 0 ) {
129- throw new IllegalArgumentException ("The type '" + type .getName () + "' is outside the allowed input types: " + associations (false ));
130- }
131- return probe ;
132- }
133-
134- @ ForceInline
135- private long offsetFor (int index ) {
136- return Unsafe .ARRAY_OBJECT_BASE_OFFSET + (long ) index * Unsafe .ARRAY_OBJECT_INDEX_SCALE ;
137- }
138-
139- @ ForceInline
140- private long nextOffset (long offset ) {
141- return offset + Unsafe .ARRAY_OBJECT_INDEX_SCALE ;
142- }
143- }
144-
145- // returns index at which the probe key is present; or if absent,
146- // (-i - 1) where i is location where element should be inserted.
147- @ ForceInline
148- private static int probe (Object [] table , Object pk ) {
149- int idx = Math .floorMod (pk .hashCode (), table .length >> 1 ) << 1 ;
150- while (true ) {
151- Object ek = table [idx ];
152- if (ek == null ) {
153- return -idx - 1 ;
154- } else if (pk .equals (ek )) {
155- return idx ;
156- } else if ((idx += 2 ) == table .length ) {
157- idx = 0 ;
158- }
159- }
160- }
161-
162- private static int availableIndex (int probe ) {
163- return -probe - 1 ;
164- }
165-
67+ /**
68+ * {@return a new stable component container that can associate any of the provided
69+ * {@code types} to components}
70+ *
71+ * @param types that can be used to associate to components
72+ * @param <T> the common type of the components. The type can be {@linkplain Object}
73+ * if there is no common super type for the components.
74+ */
16675 static <T > StableComponentContainer <T > of (Set <Class <? extends T >> types ) {
16776 // TOC TOU protection and
16877 // implicit null check of `types` and explicit null check on all its elements
@@ -171,16 +80,7 @@ static <T> StableComponentContainer<T> of(Set<Class<? extends T>> types) {
17180 for (Object type : types ) {
17281 inputs [idx ++] = Objects .requireNonNull (type );
17382 }
174-
175- // Prepopulate all the keys upfront
176- final Object [] table = new Object [inputs .length << 2 ];
177- for (Object type : inputs ) {
178- final int probe = probe (table , type );
179- assert probe < 0 ;
180- final int keyIndex = availableIndex (probe );
181- table [keyIndex ] = type ;
182- }
183- return new StableComponentContainerImpl <>(table );
83+ return StableComponentContainerImpl .of (inputs );
18484 }
18585
18686}
0 commit comments