Skip to content

Commit ee02aa3

Browse files
cpovirkGoogle Java Core Libraries
authored and
Google Java Core Libraries
committed
Rename fields to make them harder to use by accident.
Nearly all access should be performed through the various methods (e.g., `casListeners(...)`, `listeners()`). In fact, we could be principled and perform _all_ access through those methods (except of course for within the implementations of those methods themselves). I haven't done that here just out of fear that it will somehow affect performance or cause stack overflows. Accidental usage has been something that I've historically worried about in, e.g., `AbstractFuture.set(V value)`, whose parameter has had the same name as a field. That _particular_ example matters less at the moment because the field recently became `private` to a new superclass, `AbstractFutureState`, and so it's not accessible in the subclass `AbstractFuture`. But it's going to matter again: I'm likely to make the fields package-private as part of [work to migrate `guava-android` off `Unsafe`](#7742). Currently, the fields can be `private` because we call `MethodHandles.lookup()` from within `AbsractFutureState`. (Yes, it would initially seem that [we shouldn't have to](https://github.com/google/guava/blob/c7363f7fb40698bb5f99d198cc45884f38642f86/guava/src/com/google/common/util/concurrent/AbstractFutureState.java#L612-L632), but we do.) But that requires `AbstractFutureState` to refer to `MethodHandles.Lookup` in one of its method signatures\[*\], and that makes old versions of Android upset. To avoid that, I will make `value` package-private, at which point I won't need the `MethodHandles.Lookup` reference in `AbstractFutureState` itself. And when I tried making `value` package-private, _one test_ started to fail. It should have taken me less time to figure out, but I eventually discovered that the problem was that [the test refers to "`value`" inside an `AbstractFuture` subclass](https://github.com/google/guava/blob/c7363f7fb40698bb5f99d198cc45884f38642f86/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java#L78). Previously, this referred to the local variable `value` from the test method; with my change, it was instead referring to the `value` field. (I wouldn't have to have gone down the road of making the field non-`private` in the first place [if not for Java 8 compatibility](#6614 (comment)).... Still, as discussed above, this rename could protect against problems _within_ the file, too, and such problems could arise even if the field were to remain `private`.) \[*\] Or maybe I could declare the method as returning `Object` instead of `MethodHandles.Lookup`, and the caller could cast it back? But we found during [our `SequencedCollection` work](#6903) that Android (and I think maybe the JVM, but I can't find my record of this) can produce a `VerifyError` in some cases in which _implementation_ code refers to an unknown type, I think specifically when it needs to check whether a `return someThingOfTypeFoo` from that method is compatible with the return type `Bar` of the method. We _might_ be able to work around that by performing an explicit, "redundant" cast to `Object`, but I'm not even sure how to get javac to do that, and it feels very fragile, especially in the presence of optimization/minification tools. RELNOTES=n/a PiperOrigin-RevId: 741511657
1 parent c7363f7 commit ee02aa3

File tree

2 files changed

+128
-125
lines changed

2 files changed

+128
-125
lines changed

android/guava/src/com/google/common/util/concurrent/AbstractFutureState.java

+63-62
Original file line numberDiff line numberDiff line change
@@ -49,39 +49,39 @@ abstract class AbstractFutureState<V extends @Nullable Object> extends InternalF
4949
implements ListenableFuture<V> {
5050
/**
5151
* Performs a {@linkplain java.lang.invoke.VarHandle#compareAndSet compare-and-set} operation on
52-
* the {@link #listeners} field.
52+
* {@link #listenersField}.
5353
*/
5454
final boolean casListeners(@Nullable Listener expect, Listener update) {
5555
return ATOMIC_HELPER.casListeners(this, expect, update);
5656
}
5757

5858
/**
59-
* Performs a {@linkplain java.lang.invoke.VarHandle#getAndSet get-and-set} operation on the
60-
* {@link #listeners} field..
59+
* Performs a {@linkplain java.lang.invoke.VarHandle#getAndSet get-and-set} operation on {@link
60+
* #listenersField}.
6161
*/
6262
final @Nullable Listener gasListeners(Listener update) {
6363
return ATOMIC_HELPER.gasListeners(this, update);
6464
}
6565

6666
/**
6767
* Performs a {@linkplain java.lang.invoke.VarHandle#compareAndSet compare-and-set} operation on
68-
* the {@link #value} field of {@code future}.
68+
* {@link #valueField} of {@code future}.
6969
*/
7070
static boolean casValue(AbstractFutureState<?> future, @Nullable Object expect, Object update) {
7171
return ATOMIC_HELPER.casValue(future, expect, update);
7272
}
7373

7474
/** Returns the value of the future, using a volatile read. */
7575
final @Nullable Object value() {
76-
return value;
76+
return valueField;
7777
}
7878

7979
/** Returns the head of the listener stack, using a volatile read. */
8080
final @Nullable Listener listeners() {
81-
return listeners;
81+
return listenersField;
8282
}
8383

84-
/** Releases all threads in the {@link #waiters} list, and clears the list. */
84+
/** Releases all threads in the {@link #waitersField} list, and clears the list. */
8585
final void releaseWaiters() {
8686
Waiter head = gasWaiters(Waiter.TOMBSTONE);
8787
for (Waiter currentWaiter = head; currentWaiter != null; currentWaiter = currentWaiter.next) {
@@ -92,10 +92,10 @@ final void releaseWaiters() {
9292
// Gets and Timed Gets
9393
//
9494
// * Be responsive to interruption
95-
// * Don't create Waiter nodes if you aren't going to park, this helps reduce contention on the
96-
// waiters field.
97-
// * Future completion is defined by when #value becomes non-null/non DelegatingToFuture
98-
// * Future completion can be observed if the waiters field contains a TOMBSTONE
95+
// * Don't create Waiter nodes if you aren't going to park, this helps reduce contention on
96+
// waitersField.
97+
// * Future completion is defined by when #valueField becomes non-null/non DelegatingToFuture
98+
// * Future completion can be observed if the waitersField field contains a TOMBSTONE
9999

100100
// Timed Get
101101
// There are a few design constraints to consider
@@ -127,15 +127,15 @@ final V blockingGet(long timeout, TimeUnit unit)
127127
if (Thread.interrupted()) {
128128
throw new InterruptedException();
129129
}
130-
@RetainedLocalRef Object localValue = value;
130+
@RetainedLocalRef Object localValue = valueField;
131131
if (localValue != null & notInstanceOfDelegatingToFuture(localValue)) {
132132
return getDoneValue(localValue);
133133
}
134134
// we delay calling nanoTime until we know we will need to either park or spin
135135
long endNanos = remainingNanos > 0 ? System.nanoTime() + remainingNanos : 0;
136136
long_wait_loop:
137137
if (remainingNanos >= SPIN_THRESHOLD_NANOS) {
138-
Waiter oldHead = waiters;
138+
Waiter oldHead = waitersField;
139139
if (oldHead != Waiter.TOMBSTONE) {
140140
Waiter node = new Waiter();
141141
do {
@@ -151,7 +151,7 @@ final V blockingGet(long timeout, TimeUnit unit)
151151

152152
// Otherwise re-read and check doneness. If we loop then it must have been a spurious
153153
// wakeup
154-
localValue = value;
154+
localValue = valueField;
155155
if (localValue != null & notInstanceOfDelegatingToFuture(localValue)) {
156156
return getDoneValue(localValue);
157157
}
@@ -165,18 +165,18 @@ final V blockingGet(long timeout, TimeUnit unit)
165165
}
166166
}
167167
}
168-
oldHead = waiters; // re-read and loop.
168+
oldHead = waitersField; // re-read and loop.
169169
} while (oldHead != Waiter.TOMBSTONE);
170170
}
171-
// re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a
172-
// waiter.
173-
// requireNonNull is safe because value is always set before TOMBSTONE.
174-
return getDoneValue(requireNonNull(value));
171+
// re-read valueField, if we get here then we must have observed a TOMBSTONE while trying to
172+
// add a waiter.
173+
// requireNonNull is safe because valueField is always set before TOMBSTONE.
174+
return getDoneValue(requireNonNull(valueField));
175175
}
176176
// If we get here then we have remainingNanos < SPIN_THRESHOLD_NANOS and there is no node on the
177177
// waiters list
178178
while (remainingNanos > 0) {
179-
localValue = value;
179+
localValue = valueField;
180180
if (localValue != null & notInstanceOfDelegatingToFuture(localValue)) {
181181
return getDoneValue(localValue);
182182
}
@@ -226,11 +226,11 @@ final V blockingGet() throws InterruptedException, ExecutionException {
226226
if (Thread.interrupted()) {
227227
throw new InterruptedException();
228228
}
229-
@RetainedLocalRef Object localValue = value;
229+
@RetainedLocalRef Object localValue = valueField;
230230
if (localValue != null & notInstanceOfDelegatingToFuture(localValue)) {
231231
return getDoneValue(localValue);
232232
}
233-
Waiter oldHead = waiters;
233+
Waiter oldHead = waitersField;
234234
if (oldHead != Waiter.TOMBSTONE) {
235235
Waiter node = new Waiter();
236236
do {
@@ -246,19 +246,19 @@ final V blockingGet() throws InterruptedException, ExecutionException {
246246
}
247247
// Otherwise re-read and check doneness. If we loop then it must have been a spurious
248248
// wakeup
249-
localValue = value;
249+
localValue = valueField;
250250
if (localValue != null & notInstanceOfDelegatingToFuture(localValue)) {
251251
return getDoneValue(localValue);
252252
}
253253
}
254254
}
255-
oldHead = waiters; // re-read and loop.
255+
oldHead = waitersField; // re-read and loop.
256256
} while (oldHead != Waiter.TOMBSTONE);
257257
}
258-
// re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a
259-
// waiter.
260-
// requireNonNull is safe because value is always set before TOMBSTONE.
261-
return getDoneValue(requireNonNull(value));
258+
// re-read valueField, if we get here then we must have observed a TOMBSTONE while trying to add
259+
// a waiter.
260+
// requireNonNull is safe because valueField is always set before TOMBSTONE.
261+
return getDoneValue(requireNonNull(valueField));
262262
}
263263

264264
/** Constructor for use by {@link AbstractFuture}. */
@@ -296,7 +296,7 @@ final V blockingGet() throws InterruptedException, ExecutionException {
296296
GENERATE_CANCELLATION_CAUSES = generateCancellationCauses;
297297
}
298298

299-
/** Waiter links form a Treiber stack, in the {@link #waiters} field. */
299+
/** Waiter links form a Treiber stack in {@link #waitersField}. */
300300
static final class Waiter {
301301
static final Waiter TOMBSTONE = new Waiter(false /* ignored param */);
302302

@@ -310,12 +310,12 @@ static final class Waiter {
310310
Waiter(boolean unused) {}
311311

312312
Waiter() {
313-
// avoid volatile write, write is made visible by subsequent CAS on waiters field
313+
// avoid volatile write, write is made visible by subsequent CAS on waitersField field
314314
putThread(this, Thread.currentThread());
315315
}
316316

317-
// non-volatile write to the next field. Should be made visible by subsequent CAS on waiters
318-
// field.
317+
// non-volatile write to the next field. Should be made visible by a subsequent CAS on
318+
// waitersField.
319319
void setNext(@Nullable Waiter next) {
320320
putNext(this, next);
321321
}
@@ -380,8 +380,8 @@ void unpark() {
380380
}
381381
}
382382

383-
// TODO(lukes): investigate using the @Contended annotation on these fields when jdk8 is
384-
// available.
383+
// TODO(lukes): Investigate using a @Contended annotation on these fields once one is available.
384+
385385
/**
386386
* This field encodes the current state of the future.
387387
*
@@ -397,13 +397,13 @@ void unpark() {
397397
* argument.
398398
* </ul>
399399
*/
400-
private volatile @Nullable Object value;
400+
private volatile @Nullable Object valueField;
401401

402402
/** All listeners. */
403-
private volatile @Nullable Listener listeners;
403+
private volatile @Nullable Listener listenersField;
404404

405405
/** All waiting threads. */
406-
private volatile @Nullable Waiter waiters;
406+
private volatile @Nullable Waiter waitersField;
407407

408408
/** Non-volatile write of the thread to the {@link Waiter#thread} field. */
409409
private static void putThread(Waiter waiter, Thread newValue) {
@@ -416,16 +416,16 @@ private static void putNext(Waiter waiter, @Nullable Waiter newValue) {
416416
}
417417

418418
/**
419-
* Performs a {@linkplain java.lang.invoke.VarHandle#compareAndSet compare-and-set} operation on
420-
* the {@link #waiters} field.
419+
* Performs a {@linkplain java.lang.invoke.VarHandle#compareAndSet compare-and-set} operation
420+
* {@link #waitersField}.
421421
*/
422422
private boolean casWaiters(@Nullable Waiter expect, @Nullable Waiter update) {
423423
return ATOMIC_HELPER.casWaiters(this, expect, update);
424424
}
425425

426426
/**
427-
* Performs a {@linkplain java.lang.invoke.VarHandle#getAndSet get-and-set} operation on the
428-
* {@link #waiters} field.
427+
* Performs a {@linkplain java.lang.invoke.VarHandle#getAndSet get-and-set} operation on {@link
428+
* #waitersField}.
429429
*/
430430
private final @Nullable Waiter gasWaiters(Waiter update) {
431431
return ATOMIC_HELPER.gasWaiters(this, update);
@@ -447,7 +447,7 @@ private void removeWaiter(Waiter node) {
447447
restart:
448448
while (true) {
449449
Waiter pred = null;
450-
Waiter curr = waiters;
450+
Waiter curr = waitersField;
451451
if (curr == Waiter.TOMBSTONE) {
452452
return; // give up if someone is calling complete
453453
}
@@ -481,21 +481,21 @@ private abstract static class AtomicHelper {
481481
/** Non-volatile write of the waiter to the {@link Waiter#next} field. */
482482
abstract void putNext(Waiter waiter, @Nullable Waiter newValue);
483483

484-
/** Performs a CAS operation on the {@link AbstractFutureState#waiters} field. */
484+
/** Performs a CAS operation on {@link AbstractFutureState#waitersField}. */
485485
abstract boolean casWaiters(
486486
AbstractFutureState<?> future, @Nullable Waiter expect, @Nullable Waiter update);
487487

488-
/** Performs a CAS operation on the {@link AbstractFutureState#listeners} field. */
488+
/** Performs a CAS operation on {@link AbstractFutureState#listenersField}. */
489489
abstract boolean casListeners(
490490
AbstractFutureState<?> future, @Nullable Listener expect, Listener update);
491491

492-
/** Performs a GAS operation on the {@link AbstractFutureState#waiters} field. */
492+
/** Performs a GAS operation on {@link AbstractFutureState#waitersField}. */
493493
abstract @Nullable Waiter gasWaiters(AbstractFutureState<?> future, Waiter update);
494494

495-
/** Performs a GAS operation on the {@link AbstractFutureState#listeners} field. */
495+
/** Performs a GAS operation on {@link AbstractFutureState#listenersField}. */
496496
abstract @Nullable Listener gasListeners(AbstractFutureState<?> future, Listener update);
497497

498-
/** Performs a CAS operation on the {@link AbstractFutureState#value} field. */
498+
/** Performs a CAS operation on {@link AbstractFutureState#valueField}. */
499499
abstract boolean casValue(
500500
AbstractFutureState<?> future, @Nullable Object expect, Object update);
501501
}
@@ -541,10 +541,11 @@ private static final class UnsafeAtomicHelper extends AtomicHelper {
541541
}
542542
try {
543543
Class<?> abstractFutureState = AbstractFutureState.class;
544-
WAITERS_OFFSET = unsafe.objectFieldOffset(abstractFutureState.getDeclaredField("waiters"));
544+
WAITERS_OFFSET =
545+
unsafe.objectFieldOffset(abstractFutureState.getDeclaredField("waitersField"));
545546
LISTENERS_OFFSET =
546-
unsafe.objectFieldOffset(abstractFutureState.getDeclaredField("listeners"));
547-
VALUE_OFFSET = unsafe.objectFieldOffset(abstractFutureState.getDeclaredField("value"));
547+
unsafe.objectFieldOffset(abstractFutureState.getDeclaredField("listenersField"));
548+
VALUE_OFFSET = unsafe.objectFieldOffset(abstractFutureState.getDeclaredField("valueField"));
548549
WAITER_THREAD_OFFSET = unsafe.objectFieldOffset(Waiter.class.getDeclaredField("thread"));
549550
WAITER_NEXT_OFFSET = unsafe.objectFieldOffset(Waiter.class.getDeclaredField("next"));
550551
UNSAFE = unsafe;
@@ -578,7 +579,7 @@ boolean casListeners(
578579
@Override
579580
@Nullable Listener gasListeners(AbstractFutureState<?> future, Listener update) {
580581
while (true) {
581-
Listener listener = future.listeners;
582+
Listener listener = future.listenersField;
582583
if (update == listener) {
583584
return listener;
584585
}
@@ -591,7 +592,7 @@ boolean casListeners(
591592
@Override
592593
@Nullable Waiter gasWaiters(AbstractFutureState<?> future, Waiter update) {
593594
while (true) {
594-
Waiter waiter = future.waiters;
595+
Waiter waiter = future.waitersField;
595596
if (update == waiter) {
596597
return waiter;
597598
}
@@ -717,8 +718,8 @@ void putNext(Waiter waiter, @Nullable Waiter newValue) {
717718
boolean casWaiters(
718719
AbstractFutureState<?> future, @Nullable Waiter expect, @Nullable Waiter update) {
719720
synchronized (future) {
720-
if (future.waiters == expect) {
721-
future.waiters = update;
721+
if (future.waitersField == expect) {
722+
future.waitersField = update;
722723
return true;
723724
}
724725
return false;
@@ -729,8 +730,8 @@ boolean casWaiters(
729730
boolean casListeners(
730731
AbstractFutureState<?> future, @Nullable Listener expect, Listener update) {
731732
synchronized (future) {
732-
if (future.listeners == expect) {
733-
future.listeners = update;
733+
if (future.listenersField == expect) {
734+
future.listenersField = update;
734735
return true;
735736
}
736737
return false;
@@ -740,9 +741,9 @@ boolean casListeners(
740741
@Override
741742
@Nullable Listener gasListeners(AbstractFutureState<?> future, Listener update) {
742743
synchronized (future) {
743-
Listener old = future.listeners;
744+
Listener old = future.listenersField;
744745
if (old != update) {
745-
future.listeners = update;
746+
future.listenersField = update;
746747
}
747748
return old;
748749
}
@@ -751,9 +752,9 @@ boolean casListeners(
751752
@Override
752753
@Nullable Waiter gasWaiters(AbstractFutureState<?> future, Waiter update) {
753754
synchronized (future) {
754-
Waiter old = future.waiters;
755+
Waiter old = future.waitersField;
755756
if (old != update) {
756-
future.waiters = update;
757+
future.waitersField = update;
757758
}
758759
return old;
759760
}
@@ -762,8 +763,8 @@ boolean casListeners(
762763
@Override
763764
boolean casValue(AbstractFutureState<?> future, @Nullable Object expect, Object update) {
764765
synchronized (future) {
765-
if (future.value == expect) {
766-
future.value = update;
766+
if (future.valueField == expect) {
767+
future.valueField = update;
767768
return true;
768769
}
769770
return false;

0 commit comments

Comments
 (0)