diff --git a/android/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java b/android/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java
index 1ed1d10d77d6..9823f5fcc8d7 100644
--- a/android/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java
+++ b/android/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java
@@ -68,7 +68,13 @@ public static TestSuite suite() {
// corresponding method on FuturesTest in the correct classloader.
TestSuite suite = new TestSuite(AggregateFutureStateFallbackAtomicHelperTest.class.getName());
for (Method method : FuturesTest.class.getDeclaredMethods()) {
- if (Modifier.isPublic(method.getModifiers()) && method.getName().startsWith("test")) {
+ if (Modifier.isPublic(method.getModifiers())
+ && method.getName().startsWith("test")
+ /*
+ * When we block access to AtomicReferenceFieldUpdater, we can't even reflect on
+ * AbstractFuture, since it declares methods that use that type in their signatures.
+ */
+ && !method.getName().equals("testFutures_nullChecks")) {
suite.addTest(
TestSuite.createTest(
AggregateFutureStateFallbackAtomicHelperTest.class, method.getName()));
diff --git a/android/guava/src/com/google/common/util/concurrent/AbstractFuture.java b/android/guava/src/com/google/common/util/concurrent/AbstractFuture.java
index 1e3942fe0def..4b119e03b162 100644
--- a/android/guava/src/com/google/common/util/concurrent/AbstractFuture.java
+++ b/android/guava/src/com/google/common/util/concurrent/AbstractFuture.java
@@ -159,24 +159,15 @@ public final boolean cancel(boolean mayInterruptIfRunning) {
helper = new UnsafeAtomicHelper();
} catch (Exception | Error unsafeFailure) { // sneaky checked exception
thrownUnsafeFailure = unsafeFailure;
- // catch absolutely everything and fall through to our
- // 'AtomicReferenceFieldUpdaterAtomicHelper' The access control checks that ARFU does means
- // the caller class has to be AbstractFuture instead of
- // AtomicReferenceFieldUpdaterAtomicHelper, so we annoyingly define these here
+ // Catch absolutely everything and fall through to AtomicReferenceFieldUpdaterAtomicHelper.
try {
- helper =
- new AtomicReferenceFieldUpdaterAtomicHelper(
- newUpdater(Waiter.class, Thread.class, "thread"),
- newUpdater(Waiter.class, Waiter.class, "next"),
- newUpdater(AbstractFuture.class, Waiter.class, "waiters"),
- newUpdater(AbstractFuture.class, Listener.class, "listeners"),
- newUpdater(AbstractFuture.class, Object.class, "value"));
+ helper = new AtomicReferenceFieldUpdaterAtomicHelper();
} catch (Exception // sneaky checked exception
| Error atomicReferenceFieldUpdaterFailure) {
// Some Android 5.0.x Samsung devices have bugs in JDK reflection APIs that cause
// getDeclaredField to throw a NoSuchFieldException when the field is definitely there.
- // For these users fallback to a suboptimal implementation, based on synchronized. This will
- // be a definite performance hit to those users.
+ // For these users fallback to a suboptimal implementation, based on synchronized. This
+ // will be a definite performance hit to those users.
thrownAtomicReferenceFieldUpdaterFailure = atomicReferenceFieldUpdaterFailure;
helper = new SynchronizedHelper();
}
@@ -716,7 +707,7 @@ mayInterruptIfRunning, new CancellationException("Future.cancel() was called."))
*
*
The default implementation does nothing.
*
- *
This method is likely to be deprecated. Prefer to override {@link #afterDone}, consulting
+ *
This method is likely to be deprecated. Prefer to override {@link #afterDone}, checking
* {@link #wasInterrupted} to decide whether to interrupt your task.
*
* @since 10.0
@@ -1447,24 +1438,16 @@ boolean casValue(AbstractFuture> future, @Nullable Object expect, Object updat
/** {@link AtomicHelper} based on {@link AtomicReferenceFieldUpdater}. */
private static final class AtomicReferenceFieldUpdaterAtomicHelper extends AtomicHelper {
- final AtomicReferenceFieldUpdater waiterThreadUpdater;
- final AtomicReferenceFieldUpdater waiterNextUpdater;
- final AtomicReferenceFieldUpdater super AbstractFuture>, Waiter> waitersUpdater;
- final AtomicReferenceFieldUpdater super AbstractFuture>, Listener> listenersUpdater;
- final AtomicReferenceFieldUpdater super AbstractFuture>, Object> valueUpdater;
-
- AtomicReferenceFieldUpdaterAtomicHelper(
- AtomicReferenceFieldUpdater waiterThreadUpdater,
- AtomicReferenceFieldUpdater waiterNextUpdater,
- AtomicReferenceFieldUpdater super AbstractFuture>, Waiter> waitersUpdater,
- AtomicReferenceFieldUpdater super AbstractFuture>, Listener> listenersUpdater,
- AtomicReferenceFieldUpdater super AbstractFuture>, Object> valueUpdater) {
- this.waiterThreadUpdater = waiterThreadUpdater;
- this.waiterNextUpdater = waiterNextUpdater;
- this.waitersUpdater = waitersUpdater;
- this.listenersUpdater = listenersUpdater;
- this.valueUpdater = valueUpdater;
- }
+ private static final AtomicReferenceFieldUpdater waiterThreadUpdater =
+ newUpdater(Waiter.class, Thread.class, "thread");
+ private static final AtomicReferenceFieldUpdater waiterNextUpdater =
+ newUpdater(Waiter.class, Waiter.class, "next");
+ private static final AtomicReferenceFieldUpdater super AbstractFuture>, Waiter>
+ waitersUpdater = waitersUpdaterFromWithinAbstractFuture();
+ private static final AtomicReferenceFieldUpdater super AbstractFuture>, Listener>
+ listenersUpdater = listenersUpdaterFromWithinAbstractFuture();
+ private static final AtomicReferenceFieldUpdater super AbstractFuture>, Object>
+ valueUpdater = valueUpdaterFromWithinAbstractFuture();
@Override
void putThread(Waiter waiter, Thread newValue) {
@@ -1502,6 +1485,24 @@ boolean casValue(AbstractFuture> future, @Nullable Object expect, Object updat
}
}
+ /** Returns an {@link AtomicReferenceFieldUpdater} for {@link #waiters}. */
+ private static AtomicReferenceFieldUpdater super AbstractFuture>, Waiter>
+ waitersUpdaterFromWithinAbstractFuture() {
+ return newUpdater(AbstractFuture.class, Waiter.class, "waiters");
+ }
+
+ /** Returns an {@link AtomicReferenceFieldUpdater} for {@link #listeners}. */
+ private static AtomicReferenceFieldUpdater super AbstractFuture>, Listener>
+ listenersUpdaterFromWithinAbstractFuture() {
+ return newUpdater(AbstractFuture.class, Listener.class, "listeners");
+ }
+
+ /** Returns an {@link AtomicReferenceFieldUpdater} for {@link #value}. */
+ private static AtomicReferenceFieldUpdater super AbstractFuture>, Object>
+ valueUpdaterFromWithinAbstractFuture() {
+ return newUpdater(AbstractFuture.class, Object.class, "value");
+ }
+
/**
* {@link AtomicHelper} based on {@code synchronized} and volatile writes.
*
diff --git a/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java b/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java
index 1ed1d10d77d6..9823f5fcc8d7 100644
--- a/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/AggregateFutureStateFallbackAtomicHelperTest.java
@@ -68,7 +68,13 @@ public static TestSuite suite() {
// corresponding method on FuturesTest in the correct classloader.
TestSuite suite = new TestSuite(AggregateFutureStateFallbackAtomicHelperTest.class.getName());
for (Method method : FuturesTest.class.getDeclaredMethods()) {
- if (Modifier.isPublic(method.getModifiers()) && method.getName().startsWith("test")) {
+ if (Modifier.isPublic(method.getModifiers())
+ && method.getName().startsWith("test")
+ /*
+ * When we block access to AtomicReferenceFieldUpdater, we can't even reflect on
+ * AbstractFuture, since it declares methods that use that type in their signatures.
+ */
+ && !method.getName().equals("testFutures_nullChecks")) {
suite.addTest(
TestSuite.createTest(
AggregateFutureStateFallbackAtomicHelperTest.class, method.getName()));
diff --git a/guava/src/com/google/common/util/concurrent/AbstractFuture.java b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
index ad3cf5471ad4..02d8aa94bfa6 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractFuture.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
@@ -186,18 +186,9 @@ private static MethodHandles.Lookup methodHandlesLookupFromWithinAbstractFuture(
helper = new UnsafeAtomicHelper();
} catch (Exception | Error unsafeFailure) { // sneaky checked exception
thrownUnsafeFailure = unsafeFailure;
- // catch absolutely everything and fall through to our
- // 'AtomicReferenceFieldUpdaterAtomicHelper' The access control checks that ARFU does means
- // the caller class has to be AbstractFuture instead of
- // AtomicReferenceFieldUpdaterAtomicHelper, so we annoyingly define these here
+ // Catch absolutely everything and fall through to AtomicReferenceFieldUpdaterAtomicHelper.
try {
- helper =
- new AtomicReferenceFieldUpdaterAtomicHelper(
- newUpdater(Waiter.class, Thread.class, "thread"),
- newUpdater(Waiter.class, Waiter.class, "next"),
- newUpdater(AbstractFuture.class, Waiter.class, "waiters"),
- newUpdater(AbstractFuture.class, Listener.class, "listeners"),
- newUpdater(AbstractFuture.class, Object.class, "value"));
+ helper = new AtomicReferenceFieldUpdaterAtomicHelper();
} catch (Exception // sneaky checked exception
| Error atomicReferenceFieldUpdaterFailure) {
// Some Android 5.0.x Samsung devices have bugs in JDK reflection APIs that cause
@@ -1559,24 +1550,16 @@ boolean casValue(AbstractFuture> future, @Nullable Object expect, Object updat
/** {@link AtomicHelper} based on {@link AtomicReferenceFieldUpdater}. */
private static final class AtomicReferenceFieldUpdaterAtomicHelper extends AtomicHelper {
- final AtomicReferenceFieldUpdater waiterThreadUpdater;
- final AtomicReferenceFieldUpdater waiterNextUpdater;
- final AtomicReferenceFieldUpdater super AbstractFuture>, Waiter> waitersUpdater;
- final AtomicReferenceFieldUpdater super AbstractFuture>, Listener> listenersUpdater;
- final AtomicReferenceFieldUpdater super AbstractFuture>, Object> valueUpdater;
-
- AtomicReferenceFieldUpdaterAtomicHelper(
- AtomicReferenceFieldUpdater waiterThreadUpdater,
- AtomicReferenceFieldUpdater waiterNextUpdater,
- AtomicReferenceFieldUpdater super AbstractFuture>, Waiter> waitersUpdater,
- AtomicReferenceFieldUpdater super AbstractFuture>, Listener> listenersUpdater,
- AtomicReferenceFieldUpdater super AbstractFuture>, Object> valueUpdater) {
- this.waiterThreadUpdater = waiterThreadUpdater;
- this.waiterNextUpdater = waiterNextUpdater;
- this.waitersUpdater = waitersUpdater;
- this.listenersUpdater = listenersUpdater;
- this.valueUpdater = valueUpdater;
- }
+ private static final AtomicReferenceFieldUpdater waiterThreadUpdater =
+ newUpdater(Waiter.class, Thread.class, "thread");
+ private static final AtomicReferenceFieldUpdater waiterNextUpdater =
+ newUpdater(Waiter.class, Waiter.class, "next");
+ private static final AtomicReferenceFieldUpdater super AbstractFuture>, Waiter>
+ waitersUpdater = waitersUpdaterFromWithinAbstractFuture();
+ private static final AtomicReferenceFieldUpdater super AbstractFuture>, Listener>
+ listenersUpdater = listenersUpdaterFromWithinAbstractFuture();
+ private static final AtomicReferenceFieldUpdater super AbstractFuture>, Object>
+ valueUpdater = valueUpdaterFromWithinAbstractFuture();
@Override
void putThread(Waiter waiter, Thread newValue) {
@@ -1614,6 +1597,24 @@ boolean casValue(AbstractFuture> future, @Nullable Object expect, Object updat
}
}
+ /** Returns an {@link AtomicReferenceFieldUpdater} for {@link #waiters}. */
+ private static AtomicReferenceFieldUpdater super AbstractFuture>, Waiter>
+ waitersUpdaterFromWithinAbstractFuture() {
+ return newUpdater(AbstractFuture.class, Waiter.class, "waiters");
+ }
+
+ /** Returns an {@link AtomicReferenceFieldUpdater} for {@link #listeners}. */
+ private static AtomicReferenceFieldUpdater super AbstractFuture>, Listener>
+ listenersUpdaterFromWithinAbstractFuture() {
+ return newUpdater(AbstractFuture.class, Listener.class, "listeners");
+ }
+
+ /** Returns an {@link AtomicReferenceFieldUpdater} for {@link #value}. */
+ private static AtomicReferenceFieldUpdater super AbstractFuture>, Object>
+ valueUpdaterFromWithinAbstractFuture() {
+ return newUpdater(AbstractFuture.class, Object.class, "value");
+ }
+
/**
* {@link AtomicHelper} based on {@code synchronized} and volatile writes.
*