Skip to content

Commit dd2d290

Browse files
authored
Merge pull request #48406 from franz1981/lighter_ctx_state
Lighten the memory footprint of `CurrentContextState`
2 parents 5374924 + 872e4a2 commit dd2d290

File tree

1 file changed

+29
-21
lines changed

1 file changed

+29
-21
lines changed

independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -240,31 +240,23 @@ public static class CurrentContextState implements ContextState {
240240
// the default field values are set before 'this' is accessible, hence
241241
// they should be the very first value observable even in presence of
242242
// unsafe publication of this object.
243-
private static final int VALID = 0;
244-
private static final int INVALID = 1;
245-
private static final VarHandle IS_VALID;
243+
private static final VarHandle STATE_UPDATER;
246244

247-
private static final int FALSE = 0;
248-
private static final int TRUE = 1;
249-
private static final VarHandle INITIALIZED_FIRED;
250-
private static final VarHandle BEFORE_DESTROYED_FIRED;
245+
private static final byte INVALID_MASK = 0b00000001;
246+
private static final byte INITIALIZED_FIRED_MASK = 0b00000010;
247+
private static final byte BEFORE_DESTROYED_FIRED_MASK = 0b00000100;
251248

252249
static {
253250
try {
254-
IS_VALID = MethodHandles.lookup().findVarHandle(CurrentContextState.class, "isValid", int.class);
255-
INITIALIZED_FIRED = MethodHandles.lookup().findVarHandle(CurrentContextState.class, "initializedFired",
256-
int.class);
257-
BEFORE_DESTROYED_FIRED = MethodHandles.lookup().findVarHandle(CurrentContextState.class, "beforeDestroyedFired",
258-
int.class);
251+
STATE_UPDATER = MethodHandles.lookup().findVarHandle(CurrentContextState.class, "state", byte.class);
259252
} catch (ReflectiveOperationException e) {
260253
throw new Error(e);
261254
}
262255
}
263256

264257
private final ContextInstances contextInstances;
265-
private volatile int isValid;
266-
private volatile int initializedFired;
267-
private volatile int beforeDestroyedFired;
258+
// it contains 3 states: isValid, initializedFired and beforeDestroyedFired
259+
private volatile byte state;
268260

269261
CurrentContextState(ContextInstances contextInstances) {
270262
this.contextInstances = Objects.requireNonNull(contextInstances);
@@ -280,23 +272,39 @@ public Map<InjectableBean<?>, Object> getContextualInstances() {
280272
* @return {@code true} if the state was successfully invalidated, {@code false} otherwise
281273
*/
282274
boolean invalidate() {
283-
// Atomically sets the value just like AtomicBoolean.compareAndSet(boolean, boolean)
284-
return IS_VALID.compareAndSet(this, VALID, INVALID);
275+
return set(INVALID_MASK);
285276
}
286277

287278
@Override
288279
public boolean isValid() {
289-
return isValid == VALID;
280+
return isNotSet(INVALID_MASK);
290281
}
291282

292283
boolean shouldFireInitializedEvent() {
293-
return INITIALIZED_FIRED.compareAndSet(this, FALSE, TRUE);
284+
return set(INITIALIZED_FIRED_MASK);
294285
}
295286

296287
boolean shouldFireBeforeDestroyedEvent() {
297-
return BEFORE_DESTROYED_FIRED.compareAndSet(this, FALSE, TRUE);
288+
return set(BEFORE_DESTROYED_FIRED_MASK);
298289
}
299290

300-
}
291+
private boolean isNotSet(byte bitMask) {
292+
return (state & bitMask) == 0;
293+
}
294+
295+
private boolean set(byte bitMask) {
296+
byte state = this.state;
297+
for (;;) {
298+
if ((state & bitMask) != 0) {
299+
return false;
300+
}
301+
final byte newState = (byte) (state | bitMask);
302+
state = (byte) STATE_UPDATER.compareAndExchange(this, state, newState);
303+
if (state == newState) {
304+
return true;
305+
}
306+
}
307+
}
301308

309+
}
302310
}

0 commit comments

Comments
 (0)