This is an automated email from the ASF dual-hosted git repository.
fanningpj pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git
The following commit(s) were added to refs/heads/main by this push:
new db60119b42 avoid sun.misc.Unsafe by using VarHandles (#1990)
db60119b42 is described below
commit db60119b42a959fc578e88f3add5eaf865bb7411
Author: PJ Fanning <[email protected]>
AuthorDate: Sat Aug 2 12:10:52 2025 +0100
avoid sun.misc.Unsafe by using VarHandles (#1990)
* don't use unsafe to update nextName
Update Children.scala
Update Children.scala
use varhandle
Update AbstractActorCell.java
review comment
Update Children.scala
remove more usages of Unsafe
more
more
more
javafmt
Update LightArrayRevolverScheduler.scala
Update AbstractNodeQueue.java
Update AbstractBoundedNodeQueue.java
Revert "more"
This reverts commit ef119f4ebf9fa528a880dd13dd833e4e8c6effc8.
revert some promise actor changes
javafmt
* watchedBy
* Reapply "more"
This reverts commit ba2b43cd7d920a67e2e3ac9355c50c6b8169d451.
try again
* remove imports
* javafmt
* Update Unsafe.java
* Create util-unsafe-refactor.excludes
* internal api
---
.../org/apache/pekko/actor/AbstractActorRef.java | 22 +++++++------
.../pekko/actor/dungeon/AbstractActorCell.java | 36 +++++++++++----------
.../pekko/dispatch/AbstractBoundedNodeQueue.java | 37 ++++++++++++----------
.../pekko/dispatch/AbstractMessageDispatcher.java | 19 ++++++++---
.../apache/pekko/dispatch/AbstractNodeQueue.java | 33 +++++++++++--------
.../pekko/pattern/AbstractCircuitBreaker.java | 27 ++++++++++------
.../pekko/pattern/AbstractPromiseActorRef.java | 23 ++++++++------
.../main/java/org/apache/pekko/util/Unsafe.java | 2 +-
.../util-unsafe-refactor.excludes | 19 +++++++++++
.../pekko/actor/LightArrayRevolverScheduler.scala | 13 ++++----
.../apache/pekko/actor/RepointableActorRef.scala | 13 ++++----
.../org/apache/pekko/actor/dungeon/Children.scala | 29 +++++++----------
.../org/apache/pekko/actor/dungeon/Dispatch.scala | 7 ++--
.../apache/pekko/dispatch/AbstractDispatcher.scala | 12 +++----
.../org/apache/pekko/pattern/AskSupport.scala | 24 ++++++--------
.../org/apache/pekko/pattern/CircuitBreaker.scala | 28 +++++++---------
.../pekko/remote/artery/AbstractAssociation.java | 13 +++++---
.../apache/pekko/remote/artery/Association.scala | 9 ++----
18 files changed, 203 insertions(+), 163 deletions(-)
diff --git a/actor/src/main/java/org/apache/pekko/actor/AbstractActorRef.java
b/actor/src/main/java/org/apache/pekko/actor/AbstractActorRef.java
index dc7ae0413c..7d7eeac66a 100644
--- a/actor/src/main/java/org/apache/pekko/actor/AbstractActorRef.java
+++ b/actor/src/main/java/org/apache/pekko/actor/AbstractActorRef.java
@@ -13,20 +13,24 @@
package org.apache.pekko.actor;
-import org.apache.pekko.util.Unsafe;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+import org.apache.pekko.actor.Cell;
final class AbstractActorRef {
- static final long cellOffset;
- static final long lookupOffset;
+ static final VarHandle cellHandle;
+ static final VarHandle lookupHandle;
static {
try {
- cellOffset =
- Unsafe.instance.objectFieldOffset(
-
RepointableActorRef.class.getDeclaredField("_cellDoNotCallMeDirectly"));
- lookupOffset =
- Unsafe.instance.objectFieldOffset(
-
RepointableActorRef.class.getDeclaredField("_lookupDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(RepointableActorRef.class,
MethodHandles.lookup());
+
+ cellHandle =
+ lookup.findVarHandle(RepointableActorRef.class,
"_cellDoNotCallMeDirectly", Cell.class);
+ lookupHandle =
+ lookup.findVarHandle(RepointableActorRef.class,
"_lookupDoNotCallMeDirectly", Cell.class);
} catch (Throwable t) {
throw new ExceptionInInitializerError(t);
}
diff --git
a/actor/src/main/java/org/apache/pekko/actor/dungeon/AbstractActorCell.java
b/actor/src/main/java/org/apache/pekko/actor/dungeon/AbstractActorCell.java
index 3d4b867900..c7cd1410ec 100644
--- a/actor/src/main/java/org/apache/pekko/actor/dungeon/AbstractActorCell.java
+++ b/actor/src/main/java/org/apache/pekko/actor/dungeon/AbstractActorCell.java
@@ -17,35 +17,39 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import org.apache.pekko.actor.ActorCell;
-import org.apache.pekko.util.Unsafe;
+import org.apache.pekko.dispatch.Mailbox;
final class AbstractActorCell {
- static final long mailboxOffset;
- static final long childrenOffset;
+ static final VarHandle mailboxHandle;
+ static final VarHandle childrenHandle;
static final VarHandle nextNameHandle;
- static final long functionRefsOffset;
+ static final VarHandle functionRefsHandle;
static {
try {
- mailboxOffset =
- Unsafe.instance.objectFieldOffset(
- ActorCell.class.getDeclaredField(
-
"org$apache$pekko$actor$dungeon$Dispatch$$_mailboxDoNotCallMeDirectly"));
- childrenOffset =
- Unsafe.instance.objectFieldOffset(
- ActorCell.class.getDeclaredField(
-
"org$apache$pekko$actor$dungeon$Children$$_childrenRefsDoNotCallMeDirectly"));
- functionRefsOffset =
- Unsafe.instance.objectFieldOffset(
- ActorCell.class.getDeclaredField(
-
"org$apache$pekko$actor$dungeon$Children$$_functionRefsDoNotCallMeDirectly"));
MethodHandles.Lookup lookup =
MethodHandles.privateLookupIn(ActorCell.class,
MethodHandles.lookup());
+ mailboxHandle =
+ lookup.findVarHandle(
+ ActorCell.class,
+
"org$apache$pekko$actor$dungeon$Dispatch$$_mailboxDoNotCallMeDirectly",
+ Mailbox.class);
+ childrenHandle =
+ lookup.findVarHandle(
+ ActorCell.class,
+
"org$apache$pekko$actor$dungeon$Children$$_childrenRefsDoNotCallMeDirectly",
+ ChildrenContainer.class);
nextNameHandle =
lookup.findVarHandle(
ActorCell.class,
"org$apache$pekko$actor$dungeon$Children$$_nextNameDoNotCallMeDirectly",
long.class);
+ functionRefsHandle =
+ lookup.findVarHandle(
+ ActorCell.class,
+
"org$apache$pekko$actor$dungeon$Children$$_functionRefsDoNotCallMeDirectly",
+ scala.collection.immutable.Map.class);
+
} catch (Throwable t) {
throw new ExceptionInInitializerError(t);
}
diff --git
a/actor/src/main/java/org/apache/pekko/dispatch/AbstractBoundedNodeQueue.java
b/actor/src/main/java/org/apache/pekko/dispatch/AbstractBoundedNodeQueue.java
index 3ee85c929f..361fa052e4 100644
---
a/actor/src/main/java/org/apache/pekko/dispatch/AbstractBoundedNodeQueue.java
+++
b/actor/src/main/java/org/apache/pekko/dispatch/AbstractBoundedNodeQueue.java
@@ -13,7 +13,8 @@
package org.apache.pekko.dispatch;
-import org.apache.pekko.util.Unsafe;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
/**
* Lock-free bounded non-blocking multiple-producer single-consumer queue
based on the works of:
@@ -45,29 +46,27 @@ public abstract class AbstractBoundedNodeQueue<T> {
}
private void setEnq(Node<T> n) {
- Unsafe.instance.putObjectVolatile(this, enqOffset, n);
+ enqHandle.set(this, n);
}
- @SuppressWarnings("unchecked")
private Node<T> getEnq() {
- return (Node<T>)Unsafe.instance.getObjectVolatile(this, enqOffset);
+ return (Node<T>) enqHandle.get(this);
}
private boolean casEnq(Node<T> old, Node<T> nju) {
- return Unsafe.instance.compareAndSwapObject(this, enqOffset, old, nju);
+ return enqHandle.compareAndSet(this, old, nju);
}
private void setDeq(Node<T> n) {
- Unsafe.instance.putObjectVolatile(this, deqOffset, n);
+ deqHandle.set(this, n);
}
- @SuppressWarnings("unchecked")
private Node<T> getDeq() {
- return (Node<T>)Unsafe.instance.getObjectVolatile(this, deqOffset);
+ return (Node<T>) deqHandle.get(this);
}
private boolean casDeq(Node<T> old, Node<T> nju) {
- return Unsafe.instance.compareAndSwapObject(this, deqOffset, old, nju);
+ return deqHandle.compareAndSet(this, old, nju);
}
protected final Node<T> peekNode() {
@@ -183,12 +182,15 @@ public abstract class AbstractBoundedNodeQueue<T> {
}
}
- private final static long enqOffset, deqOffset;
+ private final static VarHandle enqHandle, deqHandle;
static {
try {
- enqOffset =
Unsafe.instance.objectFieldOffset(AbstractBoundedNodeQueue.class.getDeclaredField("_enqDoNotCallMeDirectly"));
- deqOffset =
Unsafe.instance.objectFieldOffset(AbstractBoundedNodeQueue.class.getDeclaredField("_deqDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(AbstractBoundedNodeQueue.class,
MethodHandles.lookup());
+
+ enqHandle = lookup.findVarHandle(AbstractBoundedNodeQueue.class,
"_enqDoNotCallMeDirectly", Node.class);
+ deqHandle = lookup.findVarHandle(AbstractBoundedNodeQueue.class,
"_deqDoNotCallMeDirectly", Node.class);
} catch(Throwable t){
throw new ExceptionInInitializerError(t);
}
@@ -202,18 +204,21 @@ public abstract class AbstractBoundedNodeQueue<T> {
@SuppressWarnings("unchecked")
public final Node<T> next() {
- return (Node<T>)Unsafe.instance.getObjectVolatile(this,
nextOffset);
+ return (Node<T>) nextHandle.get(this);
}
protected final void setNext(final Node<T> newNext) {
- Unsafe.instance.putOrderedObject(this, nextOffset, newNext);
+ nextHandle.setRelease(this, newNext);
}
- private final static long nextOffset;
+ private final static VarHandle nextHandle;
static {
try {
- nextOffset =
Unsafe.instance.objectFieldOffset(Node.class.getDeclaredField("_nextDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(Node.class,
MethodHandles.lookup());
+
+ nextHandle = lookup.findVarHandle(Node.class,
"_nextDoNotCallMeDirectly", Node.class);
} catch(Throwable t){
throw new ExceptionInInitializerError(t);
}
diff --git
a/actor/src/main/java/org/apache/pekko/dispatch/AbstractMessageDispatcher.java
b/actor/src/main/java/org/apache/pekko/dispatch/AbstractMessageDispatcher.java
index 6fafd0dd0f..06093ad041 100644
---
a/actor/src/main/java/org/apache/pekko/dispatch/AbstractMessageDispatcher.java
+++
b/actor/src/main/java/org/apache/pekko/dispatch/AbstractMessageDispatcher.java
@@ -13,16 +13,25 @@
package org.apache.pekko.dispatch;
-import org.apache.pekko.util.Unsafe;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
abstract class AbstractMessageDispatcher {
- final static long shutdownScheduleOffset;
- final static long inhabitantsOffset;
+ final static VarHandle shutdownScheduleHandle;
+ final static VarHandle inhabitantsHandle;
static {
try {
- shutdownScheduleOffset =
Unsafe.instance.objectFieldOffset(MessageDispatcher.class.getDeclaredField("_shutdownScheduleDoNotCallMeDirectly"));
- inhabitantsOffset =
Unsafe.instance.objectFieldOffset(MessageDispatcher.class.getDeclaredField("_inhabitantsDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(MessageDispatcher.class,
MethodHandles.lookup());
+ shutdownScheduleHandle = lookup.findVarHandle(
+ MessageDispatcher.class,
+ "_shutdownScheduleDoNotCallMeDirectly",
+ int.class);
+ inhabitantsHandle = lookup.findVarHandle(
+ MessageDispatcher.class,
+ "_inhabitantsDoNotCallMeDirectly",
+ long.class);
} catch(Throwable t){
throw new ExceptionInInitializerError(t);
}
diff --git
a/actor/src/main/java/org/apache/pekko/dispatch/AbstractNodeQueue.java
b/actor/src/main/java/org/apache/pekko/dispatch/AbstractNodeQueue.java
index a67ba9741b..ac8921e155 100644
--- a/actor/src/main/java/org/apache/pekko/dispatch/AbstractNodeQueue.java
+++ b/actor/src/main/java/org/apache/pekko/dispatch/AbstractNodeQueue.java
@@ -13,8 +13,8 @@
package org.apache.pekko.dispatch;
-import org.apache.pekko.util.Unsafe;
-
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -54,7 +54,7 @@ public abstract class AbstractNodeQueue<T> extends
AtomicReference<AbstractNodeQ
*/
@SuppressWarnings("unchecked")
protected final Node<T> peekNode() {
- final Node<T> tail = ((Node<T>)Unsafe.instance.getObjectVolatile(this,
tailOffset));
+ final Node<T> tail = (Node<T>) tailHandle.get(this);
Node<T> next = tail.next();
if (next == null && get() != tail) {
// if tail != head this is not going to change until producer
makes progress
@@ -110,7 +110,7 @@ public abstract class AbstractNodeQueue<T> extends
AtomicReference<AbstractNodeQ
* @return true if queue was empty at some point in the past
*/
public final boolean isEmpty() {
- return Unsafe.instance.getObjectVolatile(this, tailOffset) == get();
+ return tailHandle.get(this) == get();
}
/**
@@ -126,7 +126,7 @@ public abstract class AbstractNodeQueue<T> extends
AtomicReference<AbstractNodeQ
public final int count() {
int count = 0;
final Node<T> head = get();
- for(Node<T> n = ((Node<T>) Unsafe.instance.getObjectVolatile(this,
tailOffset)).next();
+ for(Node<T> n = ((Node<T>) tailHandle.get(this)).next();
n != null && count < Integer.MAX_VALUE;
n = n.next()) {
++count;
@@ -162,7 +162,7 @@ public abstract class AbstractNodeQueue<T> extends
AtomicReference<AbstractNodeQ
*/
@SuppressWarnings("unchecked")
public final Node<T> pollNode() {
- final Node<T> tail = (Node<T>) Unsafe.instance.getObjectVolatile(this,
tailOffset);
+ final Node<T> tail = (Node<T>) tailHandle.get(this);
Node<T> next = tail.next();
if (next == null && get() != tail) {
// if tail != head this is not going to change until producer makes
progress
@@ -175,17 +175,20 @@ public abstract class AbstractNodeQueue<T> extends
AtomicReference<AbstractNodeQ
else {
tail.value = next.value;
next.value = null;
- Unsafe.instance.putOrderedObject(this, tailOffset, next);
+ tailHandle.setRelease(this, next);
tail.setNext(null);
return tail;
}
}
- private final static long tailOffset;
+ private final static VarHandle tailHandle;
static {
try {
- tailOffset =
Unsafe.instance.objectFieldOffset(AbstractNodeQueue.class.getDeclaredField("_tailDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(AbstractNodeQueue.class,
MethodHandles.lookup());
+
+ tailHandle = lookup.findVarHandle(AbstractNodeQueue.class,
"_tailDoNotCallMeDirectly", Node.class);
} catch(Throwable t){
throw new ExceptionInInitializerError(t);
}
@@ -204,20 +207,22 @@ public abstract class AbstractNodeQueue<T> extends
AtomicReference<AbstractNodeQ
this.value = value;
}
- @SuppressWarnings("unchecked")
public final Node<T> next() {
- return (Node<T>)Unsafe.instance.getObjectVolatile(this,
nextOffset);
+ return (Node<T>) nextHandle.get(this);
}
protected final void setNext(final Node<T> newNext) {
- Unsafe.instance.putOrderedObject(this, nextOffset, newNext);
+ nextHandle.setRelease(this, newNext);
}
- private final static long nextOffset;
+ private final static VarHandle nextHandle;
static {
try {
- nextOffset =
Unsafe.instance.objectFieldOffset(Node.class.getDeclaredField("_nextDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(Node.class,
MethodHandles.lookup());
+
+ nextHandle = lookup.findVarHandle(Node.class,
"_nextDoNotCallMeDirectly", Node.class);
} catch(Throwable t){
throw new ExceptionInInitializerError(t);
}
diff --git
a/actor/src/main/java/org/apache/pekko/pattern/AbstractCircuitBreaker.java
b/actor/src/main/java/org/apache/pekko/pattern/AbstractCircuitBreaker.java
index 13e4874db6..5851d39cb6 100644
--- a/actor/src/main/java/org/apache/pekko/pattern/AbstractCircuitBreaker.java
+++ b/actor/src/main/java/org/apache/pekko/pattern/AbstractCircuitBreaker.java
@@ -13,20 +13,29 @@
package org.apache.pekko.pattern;
-import org.apache.pekko.util.Unsafe;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+import scala.concurrent.duration.FiniteDuration;
+
+import org.apache.pekko.pattern.CircuitBreaker.State;
class AbstractCircuitBreaker {
- protected static final long stateOffset;
- protected static final long resetTimeoutOffset;
+ protected static final VarHandle stateHandle;
+ protected static final VarHandle resetTimeoutHandle;
static {
try {
- stateOffset =
- Unsafe.instance.objectFieldOffset(
-
CircuitBreaker.class.getDeclaredField("_currentStateDoNotCallMeDirectly"));
- resetTimeoutOffset =
- Unsafe.instance.objectFieldOffset(
-
CircuitBreaker.class.getDeclaredField("_currentResetTimeoutDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(CircuitBreaker.class,
MethodHandles.lookup());
+ stateHandle =
+ lookup.findVarHandle(
+ CircuitBreaker.class, "_currentStateDoNotCallMeDirectly",
State.class);
+ resetTimeoutHandle =
+ lookup.findVarHandle(
+ CircuitBreaker.class,
+ "_currentResetTimeoutDoNotCallMeDirectly",
+ FiniteDuration.class);
} catch (Throwable t) {
throw new ExceptionInInitializerError(t);
}
diff --git
a/actor/src/main/java/org/apache/pekko/pattern/AbstractPromiseActorRef.java
b/actor/src/main/java/org/apache/pekko/pattern/AbstractPromiseActorRef.java
index f6cf890071..25ec8825f9 100644
--- a/actor/src/main/java/org/apache/pekko/pattern/AbstractPromiseActorRef.java
+++ b/actor/src/main/java/org/apache/pekko/pattern/AbstractPromiseActorRef.java
@@ -13,20 +13,25 @@
package org.apache.pekko.pattern;
-import org.apache.pekko.util.Unsafe;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
final class AbstractPromiseActorRef {
- static final long stateOffset;
- static final long watchedByOffset;
+ static final VarHandle stateHandle;
+ static final VarHandle watchedByHandle;
static {
try {
- stateOffset =
- Unsafe.instance.objectFieldOffset(
-
PromiseActorRef.class.getDeclaredField("_stateDoNotCallMeDirectly"));
- watchedByOffset =
- Unsafe.instance.objectFieldOffset(
-
PromiseActorRef.class.getDeclaredField("_watchedByDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(PromiseActorRef.class,
MethodHandles.lookup());
+
+ stateHandle =
+ lookup.findVarHandle(PromiseActorRef.class,
"_stateDoNotCallMeDirectly", Object.class);
+ watchedByHandle =
+ lookup.findVarHandle(
+ PromiseActorRef.class,
+ "_watchedByDoNotCallMeDirectly",
+ scala.collection.immutable.Set.class);
} catch (Throwable t) {
throw new ExceptionInInitializerError(t);
}
diff --git a/actor/src/main/java/org/apache/pekko/util/Unsafe.java
b/actor/src/main/java/org/apache/pekko/util/Unsafe.java
index faaf820d3c..535d84cac2 100644
--- a/actor/src/main/java/org/apache/pekko/util/Unsafe.java
+++ b/actor/src/main/java/org/apache/pekko/util/Unsafe.java
@@ -21,7 +21,7 @@ import java.nio.charset.StandardCharsets;
/** INTERNAL API */
@InternalApi
public final class Unsafe {
- public static final sun.misc.Unsafe instance;
+ private static final sun.misc.Unsafe instance;
private static final long stringValueFieldOffset;
private static final int copyUSAsciiStrToBytesAlgorithm;
diff --git
a/actor/src/main/mima-filters/2.0.x.backwards.excludes/util-unsafe-refactor.excludes
b/actor/src/main/mima-filters/2.0.x.backwards.excludes/util-unsafe-refactor.excludes
new file mode 100644
index 0000000000..abc7d41e41
--- /dev/null
+++
b/actor/src/main/mima-filters/2.0.x.backwards.excludes/util-unsafe-refactor.excludes
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Switch to VarHandles means that we don't need Unsafe.instance to be
accessible
+ProblemFilters.exclude[MissingFieldProblem]("org.apache.pekko.util.Unsafe.instance")
diff --git
a/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
b/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
index 2f05d48680..eb947e5124 100644
---
a/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
+++
b/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
@@ -14,10 +14,11 @@
package org.apache.pekko.actor
import java.io.Closeable
+import java.lang.invoke.{ MethodHandles, VarHandle }
import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.{ AtomicLong, AtomicReference }
-import scala.annotation.{ nowarn, tailrec }
+import scala.annotation.tailrec
import scala.collection.immutable
import scala.concurrent.{ Await, ExecutionContext, Future, Promise }
import scala.concurrent.duration._
@@ -29,7 +30,6 @@ import pekko.actor.Scheduler.AtomicCancellable
import pekko.dispatch.AbstractNodeQueue
import pekko.event.LoggingAdapter
import pekko.util.Helpers
-import pekko.util.Unsafe.{ instance => unsafe }
/**
* This scheduler implementation is based on a revolving wheel of buckets,
@@ -355,9 +355,10 @@ class LightArrayRevolverScheduler(config: Config, log:
LoggingAdapter, threadFac
}
object LightArrayRevolverScheduler {
- @nowarn("msg=deprecated")
- private[this] val taskOffset =
- unsafe.objectFieldOffset(classOf[TaskHolder].getDeclaredField("task")):
@nowarn("cat=deprecation")
+ private[this] val taskHandle: VarHandle = {
+ val lookup = MethodHandles.privateLookupIn(classOf[TaskHolder],
MethodHandles.lookup())
+ lookup.findVarHandle(classOf[TaskHolder], "task", classOf[Runnable])
+ }
private class TaskQueue extends AbstractNodeQueue[TaskHolder]
@@ -376,7 +377,7 @@ object LightArrayRevolverScheduler {
private final def extractTask(replaceWith: Runnable): Runnable =
task match {
case t @ (ExecutedTask | CancelledTask) => t
- case x => if
(unsafe.compareAndSwapObject(this, taskOffset, x, replaceWith):
@nowarn("cat=deprecation")) x
+ case x => if
(taskHandle.compareAndSet(this, x, replaceWith)) x
else extractTask(replaceWith)
}
diff --git
a/actor/src/main/scala/org/apache/pekko/actor/RepointableActorRef.scala
b/actor/src/main/scala/org/apache/pekko/actor/RepointableActorRef.scala
index 1093ec5379..96e821812d 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/RepointableActorRef.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/RepointableActorRef.scala
@@ -27,7 +27,7 @@ import pekko.actor.dungeon.ChildrenContainer
import pekko.dispatch._
import pekko.dispatch.sysmsg._
import pekko.event.Logging.Warning
-import pekko.util.{ unused, Unsafe }
+import pekko.util.unused
/**
* This actor ref starts out with some dummy cell (by default just enqueuing
@@ -47,7 +47,7 @@ private[pekko] class RepointableActorRef(
extends ActorRefWithCell
with RepointableRef {
- import AbstractActorRef.{ cellOffset, lookupOffset }
+ import AbstractActorRef.{ cellHandle, lookupHandle }
/*
* H E R E B E D R A G O N S !
@@ -66,20 +66,19 @@ private[pekko] class RepointableActorRef(
_lookupDoNotCallMeDirectly
}
- def underlying: Cell =
- Unsafe.instance.getObjectVolatile(this, cellOffset).asInstanceOf[Cell]:
@nowarn("cat=deprecation")
- def lookup = Unsafe.instance.getObjectVolatile(this,
lookupOffset).asInstanceOf[Cell]: @nowarn("cat=deprecation")
+ def underlying: Cell = cellHandle.get(this)
+ def lookup: Cell = lookupHandle.get(this)
@tailrec
final def swapCell(next: Cell): Cell = {
val old = underlying
- if (Unsafe.instance.compareAndSwapObject(this, cellOffset, old, next):
@nowarn("cat=deprecation")) old
+ if (cellHandle.compareAndSet(this, old, next)) old
else swapCell(next)
}
@tailrec final def swapLookup(next: Cell): Cell = {
val old = lookup
- if (Unsafe.instance.compareAndSwapObject(this, lookupOffset, old, next):
@nowarn("cat=deprecation")) old
+ if (lookupHandle.compareAndSet(this, old, next)) old
else swapLookup(next)
}
diff --git a/actor/src/main/scala/org/apache/pekko/actor/dungeon/Children.scala
b/actor/src/main/scala/org/apache/pekko/actor/dungeon/Children.scala
index 37beef6073..02b6d0ed4b 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/dungeon/Children.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/dungeon/Children.scala
@@ -23,7 +23,7 @@ import org.apache.pekko
import pekko.actor._
import pekko.annotation.InternalStableApi
import pekko.serialization.{ Serialization, SerializationExtension,
Serializers }
-import pekko.util.{ Helpers, Unsafe }
+import pekko.util.Helpers
private[pekko] object Children {
val GetNobody = () => Nobody
@@ -38,11 +38,9 @@ private[pekko] trait Children { this: ActorCell =>
private var _childrenRefsDoNotCallMeDirectly: ChildrenContainer =
EmptyChildrenContainer
def childrenRefs: ChildrenContainer =
- Unsafe.instance.getObjectVolatile(this,
AbstractActorCell.childrenOffset).asInstanceOf[ChildrenContainer]: @nowarn(
- "cat=deprecation")
+ AbstractActorCell.childrenHandle.get(this)
final def children: immutable.Iterable[ActorRef] = childrenRefs.children
- @nowarn("msg=deprecated")
final def getChildren(): java.lang.Iterable[ActorRef] = {
import pekko.util.ccompat.JavaConverters._
children.asJava
@@ -64,10 +62,9 @@ private[pekko] trait Children { this: ActorCell =>
private[pekko] def attachChild(props: Props, name: String, systemService:
Boolean): ActorRef =
makeChild(this, props, checkName(name), async = true, systemService =
systemService)
- @nowarn @volatile private var _functionRefsDoNotCallMeDirectly =
Map.empty[String, FunctionRef]
+ @nowarn @volatile private var _functionRefsDoNotCallMeDirectly =
immutable.Map.empty[String, FunctionRef]
private def functionRefs: Map[String, FunctionRef] =
- Unsafe.instance.getObjectVolatile(this,
AbstractActorCell.functionRefsOffset).asInstanceOf[Map[String,
- FunctionRef]]: @nowarn("cat=deprecation")
+ AbstractActorCell.functionRefsHandle.get(this)
private[pekko] def getFunctionRefOrNobody(name: String, uid: Int =
ActorCell.undefinedUid): InternalActorRef =
functionRefs.getOrElse(name, Children.GetNobody()) match {
@@ -86,8 +83,7 @@ private[pekko] trait Children { this: ActorCell =>
@tailrec def rec(): Unit = {
val old = functionRefs
val added = old.updated(childPath.name, ref)
- if (!Unsafe.instance.compareAndSwapObject(this,
AbstractActorCell.functionRefsOffset, old, added): @nowarn(
- "cat=deprecation")) rec()
+ if (!AbstractActorCell.functionRefsHandle.compareAndSet(this, old,
added)) rec()
}
rec()
@@ -102,8 +98,7 @@ private[pekko] trait Children { this: ActorCell =>
if (!old.contains(name)) false
else {
val removed = old - name
- if (!Unsafe.instance.compareAndSwapObject(this,
AbstractActorCell.functionRefsOffset, old, removed): @nowarn(
- "cat=deprecation")) rec()
+ if (!AbstractActorCell.functionRefsHandle.compareAndSet(this, old,
removed)) rec()
else {
ref.stop()
true
@@ -114,9 +109,9 @@ private[pekko] trait Children { this: ActorCell =>
}
protected def stopFunctionRefs(): Unit = {
- val refs = Unsafe.instance
- .getAndSetObject(this, AbstractActorCell.functionRefsOffset, Map.empty)
- .asInstanceOf[Map[String, FunctionRef]]: @nowarn("cat=deprecation")
+ val refs = AbstractActorCell.functionRefsHandle
+ .getAndSet(this, Map.empty)
+ .asInstanceOf[Map[String, FunctionRef]]
refs.valuesIterator.foreach(_.stop())
}
@@ -155,8 +150,7 @@ private[pekko] trait Children { this: ActorCell =>
* low level CAS helpers
*/
private final def swapChildrenRefs(oldChildren: ChildrenContainer,
newChildren: ChildrenContainer): Boolean =
- Unsafe.instance.compareAndSwapObject(this,
AbstractActorCell.childrenOffset, oldChildren, newChildren): @nowarn(
- "cat=deprecation")
+ AbstractActorCell.childrenHandle.compareAndSet(this, oldChildren,
newChildren)
@tailrec final def reserveChild(name: String): Boolean = {
val c = childrenRefs
@@ -189,8 +183,7 @@ private[pekko] trait Children { this: ActorCell =>
}
final protected def setTerminated(): Unit =
- Unsafe.instance.putObjectVolatile(this, AbstractActorCell.childrenOffset,
TerminatedChildrenContainer): @nowarn(
- "cat=deprecation")
+ AbstractActorCell.childrenHandle.set(this, TerminatedChildrenContainer)
/*
* ActorCell-internal API
diff --git a/actor/src/main/scala/org/apache/pekko/actor/dungeon/Dispatch.scala
b/actor/src/main/scala/org/apache/pekko/actor/dungeon/Dispatch.scala
index 495b4a782d..0b1dbd88a0 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/dungeon/Dispatch.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/dungeon/Dispatch.scala
@@ -31,7 +31,6 @@ import pekko.dispatch.sysmsg._
import pekko.event.Logging.Error
import pekko.serialization.{ DisabledJavaSerializer, SerializationExtension,
Serializers }
import pekko.serialization.Serialization
-import pekko.util.Unsafe
@SerialVersionUID(1L)
final case class SerializationCheckFailedException private[dungeon] (msg:
Object, cause: Throwable)
@@ -53,14 +52,12 @@ private[pekko] trait Dispatch { this: ActorCell =>
}
final def mailbox: Mailbox =
- Unsafe.instance.getObjectVolatile(this,
AbstractActorCell.mailboxOffset).asInstanceOf[Mailbox]: @nowarn(
- "cat=deprecation")
+ AbstractActorCell.mailboxHandle.get(this)
@tailrec
final def swapMailbox(newMailbox: Mailbox): Mailbox = {
val oldMailbox = mailbox
- if (!Unsafe.instance.compareAndSwapObject(this,
AbstractActorCell.mailboxOffset, oldMailbox, newMailbox): @nowarn(
- "cat=deprecation"))
+ if (!AbstractActorCell.mailboxHandle.compareAndSet(this, oldMailbox,
newMailbox))
swapMailbox(newMailbox)
else oldMailbox
}
diff --git
a/actor/src/main/scala/org/apache/pekko/dispatch/AbstractDispatcher.scala
b/actor/src/main/scala/org/apache/pekko/dispatch/AbstractDispatcher.scala
index dfacb8908b..5a0e98f1d1 100644
--- a/actor/src/main/scala/org/apache/pekko/dispatch/AbstractDispatcher.scala
+++ b/actor/src/main/scala/org/apache/pekko/dispatch/AbstractDispatcher.scala
@@ -28,7 +28,7 @@ import pekko.dispatch.affinity.AffinityPoolConfigurator
import pekko.dispatch.sysmsg._
import pekko.event.EventStream
import pekko.event.Logging.{ emptyMDC, Debug, Error, LogEventException,
Warning }
-import pekko.util.{ unused, Index, Unsafe }
+import pekko.util.{ unused, Index }
import com.typesafe.config.Config
@@ -109,7 +109,7 @@ abstract class MessageDispatcher(val configurator:
MessageDispatcherConfigurator
with BatchingExecutor
with ExecutionContextExecutor {
- import AbstractMessageDispatcher.{ inhabitantsOffset, shutdownScheduleOffset
}
+ import AbstractMessageDispatcher.{ inhabitantsHandle, shutdownScheduleHandle
}
import MessageDispatcher._
import configurator.prerequisites
@@ -124,7 +124,7 @@ abstract class MessageDispatcher(val configurator:
MessageDispatcherConfigurator
}
private final def addInhabitants(add: Long): Long = {
- val old = Unsafe.instance.getAndAddLong(this, inhabitantsOffset, add):
@nowarn("cat=deprecation")
+ val old: Long = inhabitantsHandle.getAndAdd(this, add)
val ret = old + add
if (ret < 0) {
// We haven't succeeded in decreasing the inhabitants yet but the simple
fact that we're trying to
@@ -136,12 +136,12 @@ abstract class MessageDispatcher(val configurator:
MessageDispatcherConfigurator
ret
}
- final def inhabitants: Long = Unsafe.instance.getLongVolatile(this,
inhabitantsOffset): @nowarn("cat=deprecation")
+ final def inhabitants: Long = inhabitantsHandle.get(this)
private final def shutdownSchedule: Int =
- Unsafe.instance.getIntVolatile(this, shutdownScheduleOffset):
@nowarn("cat=deprecation")
+ shutdownScheduleHandle.get(this)
private final def updateShutdownSchedule(expect: Int, update: Int): Boolean =
- Unsafe.instance.compareAndSwapInt(this, shutdownScheduleOffset, expect,
update): @nowarn("cat=deprecation")
+ shutdownScheduleHandle.compareAndSet(this, expect, update)
/**
* Creates and returns a mailbox for the given actor.
diff --git a/actor/src/main/scala/org/apache/pekko/pattern/AskSupport.scala
b/actor/src/main/scala/org/apache/pekko/pattern/AskSupport.scala
index 4cbe494124..d784344350 100644
--- a/actor/src/main/scala/org/apache/pekko/pattern/AskSupport.scala
+++ b/actor/src/main/scala/org/apache/pekko/pattern/AskSupport.scala
@@ -16,11 +16,11 @@ package org.apache.pekko.pattern
import java.net.URLEncoder
import java.util.concurrent.TimeoutException
-import scala.annotation.tailrec
+import scala.annotation.{ nowarn, tailrec }
+import scala.collection.immutable
import scala.concurrent.{ Future, Promise }
import scala.language.implicitConversions
import scala.util.{ Failure, Success }
-import scala.annotation.nowarn
import scala.util.control.NoStackTrace
import org.apache.pekko
@@ -28,9 +28,7 @@ import pekko.actor._
import pekko.annotation.{ InternalApi, InternalStableApi }
import pekko.dispatch.ExecutionContexts
import pekko.dispatch.sysmsg._
-import pekko.util.{ Timeout, Unsafe }
-import pekko.util.ByteString
-import pekko.util.unused
+import pekko.util.{ unused, ByteString, Timeout }
/**
* This is what is used to complete a Future that is returned from an ask/?
call,
@@ -518,7 +516,7 @@ private[pekko] final class PromiseActorRef(
_mcn: String,
refPathPrefix: String)
extends MinimalActorRef {
- import AbstractPromiseActorRef.{ stateOffset, watchedByOffset }
+ import AbstractPromiseActorRef.{ stateHandle, watchedByHandle }
import PromiseActorRef._
// This is necessary for weaving the PromiseActorRef into the asked message,
i.e. the replyTo pattern.
@@ -542,18 +540,17 @@ private[pekko] final class PromiseActorRef(
@volatile
@nowarn("msg=is never updated")
- private[this] var _watchedByDoNotCallMeDirectly: Set[ActorRef] =
ActorCell.emptyActorRefSet
+ private[this] var _watchedByDoNotCallMeDirectly: immutable.Set[ActorRef] =
ActorCell.emptyActorRefSet
@nowarn private def _preventPrivateUnusedErasure = {
_stateDoNotCallMeDirectly
_watchedByDoNotCallMeDirectly
}
- private[this] def watchedBy: Set[ActorRef] =
- Unsafe.instance.getObjectVolatile(this,
watchedByOffset).asInstanceOf[Set[ActorRef]]: @nowarn("cat=deprecation")
+ private[this] def watchedBy: Set[ActorRef] = watchedByHandle.get(this)
private[this] def updateWatchedBy(oldWatchedBy: Set[ActorRef], newWatchedBy:
Set[ActorRef]): Boolean =
- Unsafe.instance.compareAndSwapObject(this, watchedByOffset, oldWatchedBy,
newWatchedBy): @nowarn("cat=deprecation")
+ watchedByHandle.compareAndSet(this, oldWatchedBy, newWatchedBy)
@tailrec // Returns false if the Promise is already completed
private[this] final def addWatcher(watcher: ActorRef): Boolean = watchedBy
match {
@@ -573,13 +570,12 @@ private[pekko] final class PromiseActorRef(
case other => if (!updateWatchedBy(other, null)) clearWatchers() else other
}
- private[this] def state: AnyRef = Unsafe.instance.getObjectVolatile(this,
stateOffset): @nowarn("cat=deprecation")
+ private[this] def state: AnyRef = stateHandle.get(this)
private[this] def updateState(oldState: AnyRef, newState: AnyRef): Boolean =
- Unsafe.instance.compareAndSwapObject(this, stateOffset, oldState,
newState): @nowarn("cat=deprecation")
+ stateHandle.compareAndSet(this, oldState, newState)
- private[this] def setState(newState: AnyRef): Unit =
- Unsafe.instance.putObjectVolatile(this, stateOffset, newState):
@nowarn("cat=deprecation")
+ private[this] def setState(newState: AnyRef): Unit = stateHandle.set(this,
newState)
override def getParent: InternalActorRef = provider.tempContainer
diff --git a/actor/src/main/scala/org/apache/pekko/pattern/CircuitBreaker.scala
b/actor/src/main/scala/org/apache/pekko/pattern/CircuitBreaker.scala
index cd4a130e6b..a0fd3cfee5 100644
--- a/actor/src/main/scala/org/apache/pekko/pattern/CircuitBreaker.scala
+++ b/actor/src/main/scala/org/apache/pekko/pattern/CircuitBreaker.scala
@@ -30,9 +30,9 @@ import pekko.PekkoException
import pekko.actor.{ ExtendedActorSystem, Scheduler }
import pekko.dispatch.ExecutionContexts.parasitic
import pekko.pattern.internal.{ CircuitBreakerNoopTelemetry,
CircuitBreakerTelemetry }
+import pekko.annotation.InternalApi
import pekko.util.FutureConverters._
import pekko.util.JavaDurationConverters._
-import pekko.util.Unsafe
/**
* Companion object providing factory methods for Circuit Breaker which runs
callbacks in caller's thread
@@ -274,41 +274,34 @@ class CircuitBreaker(
}
/**
- * Helper method for access to underlying state via Unsafe
+ * Helper method for access to underlying state via VarHandle
*
* @param oldState Previous state on transition
* @param newState Next state on transition
* @return Whether the previous state matched correctly
*/
private[this] def swapState(oldState: State, newState: State): Boolean =
- Unsafe.instance.compareAndSwapObject(this,
AbstractCircuitBreaker.stateOffset, oldState, newState): @nowarn(
- "cat=deprecation")
+ AbstractCircuitBreaker.stateHandle.compareAndSet(this, oldState, newState)
/**
- * Helper method for accessing underlying state via Unsafe
+ * Helper method for accessing underlying state via VarHandle
*
* @return Reference to current state
*/
private[this] def currentState: State =
- Unsafe.instance.getObjectVolatile(this,
AbstractCircuitBreaker.stateOffset).asInstanceOf[State]: @nowarn(
- "cat=deprecation")
+ AbstractCircuitBreaker.stateHandle.get(this)
/**
- * Helper method for updating the underlying resetTimeout via Unsafe
+ * Helper method for updating the underlying resetTimeout via VarHandle
*/
private[this] def swapResetTimeout(oldResetTimeout: FiniteDuration,
newResetTimeout: FiniteDuration): Boolean =
- Unsafe.instance.compareAndSwapObject(
- this,
- AbstractCircuitBreaker.resetTimeoutOffset,
- oldResetTimeout,
- newResetTimeout): @nowarn("cat=deprecation")
+ AbstractCircuitBreaker.resetTimeoutHandle.compareAndSet(this,
oldResetTimeout, newResetTimeout)
/**
- * Helper method for accessing to the underlying resetTimeout via Unsafe
+ * Helper method for accessing to the underlying resetTimeout via VarHandle
*/
private[this] def currentResetTimeout: FiniteDuration =
- Unsafe.instance.getObjectVolatile(this,
AbstractCircuitBreaker.resetTimeoutOffset).asInstanceOf[
- FiniteDuration]: @nowarn("cat=deprecation")
+ AbstractCircuitBreaker.resetTimeoutHandle.get(this)
/**
* Wraps invocations of asynchronous calls that need to be protected.
@@ -777,7 +770,8 @@ class CircuitBreaker(
/**
* Internal state abstraction
*/
- private sealed trait State {
+ @InternalApi
+ private[pattern] sealed trait State {
private val listeners = new CopyOnWriteArrayList[Runnable]
/**
diff --git
a/remote/src/main/java/org/apache/pekko/remote/artery/AbstractAssociation.java
b/remote/src/main/java/org/apache/pekko/remote/artery/AbstractAssociation.java
index 2ee9d60ff4..8c13799f87 100644
---
a/remote/src/main/java/org/apache/pekko/remote/artery/AbstractAssociation.java
+++
b/remote/src/main/java/org/apache/pekko/remote/artery/AbstractAssociation.java
@@ -13,16 +13,19 @@
package org.apache.pekko.remote.artery;
-import org.apache.pekko.util.Unsafe;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
class AbstractAssociation {
- protected static final long sharedStateOffset;
+ protected static final VarHandle sharedStateHandle;
static {
try {
- sharedStateOffset =
- Unsafe.instance.objectFieldOffset(
-
Association.class.getDeclaredField("_sharedStateDoNotCallMeDirectly"));
+ MethodHandles.Lookup lookup =
+ MethodHandles.privateLookupIn(Association.class,
MethodHandles.lookup());
+ sharedStateHandle =
+ lookup.findVarHandle(
+ Association.class, "_sharedStateDoNotCallMeDirectly",
AssociationState.class);
} catch (Throwable t) {
throw new ExceptionInInitializerError(t);
}
diff --git
a/remote/src/main/scala/org/apache/pekko/remote/artery/Association.scala
b/remote/src/main/scala/org/apache/pekko/remote/artery/Association.scala
index 7da5370d0c..48a8d4e44e 100644
--- a/remote/src/main/scala/org/apache/pekko/remote/artery/Association.scala
+++ b/remote/src/main/scala/org/apache/pekko/remote/artery/Association.scala
@@ -67,7 +67,6 @@ import pekko.stream.scaladsl.MergeHub
import pekko.stream.scaladsl.Source
import pekko.util.OptionVal
import pekko.util.PrettyDuration._
-import pekko.util.Unsafe
import pekko.util.WildcardIndex
import pekko.util.ccompat._
@@ -264,22 +263,20 @@ private[remote] class Association(
private[artery] var _sharedStateDoNotCallMeDirectly: AssociationState =
AssociationState()
/**
- * Helper method for access to underlying state via Unsafe
+ * Helper method for access to underlying state via VarHandle
*
* @param oldState Previous state
* @param newState Next state on transition
* @return Whether the previous state matched correctly
*/
private[artery] def swapState(oldState: AssociationState, newState:
AssociationState): Boolean =
- Unsafe.instance.compareAndSwapObject(this,
AbstractAssociation.sharedStateOffset, oldState, newState): @nowarn(
- "cat=deprecation")
+ AbstractAssociation.sharedStateHandle.compareAndSet(this, oldState,
newState)
/**
* @return Reference to current shared state
*/
def associationState: AssociationState =
- Unsafe.instance.getObjectVolatile(this,
AbstractAssociation.sharedStateOffset).asInstanceOf[
- AssociationState]: @nowarn("cat=deprecation")
+ AbstractAssociation.sharedStateHandle.get(this)
def setControlIdleKillSwitch(killSwitch: OptionVal[SharedKillSwitch]): Unit
= {
val current = associationState
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]