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 c11434abb4 remove final use of sun.misc.Unsafe (#1995)
c11434abb4 is described below

commit c11434abb42eb7273593bb307e7654e1c8fc8532
Author: PJ Fanning <[email protected]>
AuthorDate: Thu Aug 7 09:36:46 2025 +0100

    remove final use of sun.misc.Unsafe (#1995)
    
    * remove final use of sun.misc.Unsafe
    
    * Update PekkoBuild.scala
    
    * update exception handling
    
    * Update Unsafe.java
---
 .../apache/pekko/util/AsciiStringCopySpec.scala    |  1 -
 .../main/java/org/apache/pekko/util/Unsafe.java    | 94 ++++++----------------
 project/PekkoBuild.scala                           |  3 +-
 3 files changed, 24 insertions(+), 74 deletions(-)

diff --git 
a/actor-tests/src/test/scala/org/apache/pekko/util/AsciiStringCopySpec.scala 
b/actor-tests/src/test/scala/org/apache/pekko/util/AsciiStringCopySpec.scala
index 857a0f8ef5..3c35b7549b 100644
--- a/actor-tests/src/test/scala/org/apache/pekko/util/AsciiStringCopySpec.scala
+++ b/actor-tests/src/test/scala/org/apache/pekko/util/AsciiStringCopySpec.scala
@@ -26,7 +26,6 @@ class AsciiStringCopySpec extends AnyWordSpec with Matchers {
       // this is known to fail with JDK 11 on ARM32 (Raspberry Pi),
       // and therefore algorithm 0 is selected on that architecture
       Unsafe.testUSAsciiStrToBytesAlgorithm1("abc") should ===(true)
-      Unsafe.testUSAsciiStrToBytesAlgorithm2("abc") should ===(false)
     }
 
     "copy string internal representation successfully" in {
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 535d84cac2..2b12522844 100644
--- a/actor/src/main/java/org/apache/pekko/util/Unsafe.java
+++ b/actor/src/main/java/org/apache/pekko/util/Unsafe.java
@@ -15,47 +15,37 @@ package org.apache.pekko.util;
 
 import org.apache.pekko.annotation.InternalApi;
 
-import java.lang.reflect.Field;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.nio.charset.StandardCharsets;
 
 /** INTERNAL API */
 @InternalApi
 public final class Unsafe {
-  private static final sun.misc.Unsafe instance;
-
-  private static final long stringValueFieldOffset;
+  private static final VarHandle stringValueFieldHandle;
   private static final int copyUSAsciiStrToBytesAlgorithm;
 
   static {
     try {
-      sun.misc.Unsafe found = null;
-      for (Field field : sun.misc.Unsafe.class.getDeclaredFields()) {
-        if (field.getType() == sun.misc.Unsafe.class) {
-          field.setAccessible(true);
-          found = (sun.misc.Unsafe) field.get(null);
-          break;
-        }
-      }
-      if (found == null) throw new IllegalStateException("Can't find instance 
of sun.misc.Unsafe");
-      else instance = found;
-
-      long fo;
+      VarHandle handle;
       try {
-        fo = 
instance.objectFieldOffset(String.class.getDeclaredField("value"));
-      } catch (NoSuchFieldException nsfe) {
-        // The platform's implementation of String doesn't have a 'value' 
field, so we have to use
-        // algorithm 0
-        fo = -1;
+        MethodHandles.Lookup lookup =
+            MethodHandles.privateLookupIn(String.class, 
MethodHandles.lookup());
+        handle = lookup.findVarHandle(String.class, "value", byte[].class);
+      } catch (NoSuchFieldException | IllegalAccessException e) {
+        // The platform's implementation of String doesn't have a 'value' field
+        // or the field is inaccessible, so we have to use algorithm 0.
+        // You need `--add-opens=java.base/java.lang=ALL-UNNAMED` or similar 
to access it.
+        handle = null;
       }
-      stringValueFieldOffset = fo;
+      stringValueFieldHandle = handle;
 
-      if (stringValueFieldOffset > -1) {
-        // Select optimization algorithm for `copyUSAciiBytesToStr`.
+      if (handle != null) {
+        // Select optimization algorithm for `copyUSAsciiBytesToStr`.
         // For example algorithm 1 will fail with JDK 11 on ARM32 (Raspberry 
Pi),
         // and therefore algorithm 0 is selected on that architecture.
         String testStr = "abc";
         if (testUSAsciiStrToBytesAlgorithm1(testStr)) 
copyUSAsciiStrToBytesAlgorithm = 1;
-        else if (testUSAsciiStrToBytesAlgorithm2(testStr)) 
copyUSAsciiStrToBytesAlgorithm = 2;
         else copyUSAsciiStrToBytesAlgorithm = 0;
       } else
         // We know so little about the platform's String implementation that 
we have
@@ -70,12 +60,12 @@ public final class Unsafe {
     try {
       byte[] bytes = new byte[str.length()];
 
-      // copy of implementation in copyUSAciiBytesToStr
+      // copy of implementation in copyUSAsciiBytesToStr
       byte[] strBytes = str.getBytes(StandardCharsets.US_ASCII);
       System.arraycopy(strBytes, 0, bytes, 0, str.length());
       // end copy
 
-      String result = copyUSAciiBytesToStr(str.length(), bytes);
+      String result = copyUSAsciiBytesToStr(str.length(), bytes);
       return str.equals(result);
     } catch (Throwable all) {
       return false;
@@ -86,38 +76,19 @@ public final class Unsafe {
     try {
       byte[] bytes = new byte[str.length()];
 
-      // copy of implementation in copyUSAciiBytesToStr
-      final byte[] chars = (byte[]) instance.getObject(str, 
stringValueFieldOffset);
+      // copy of implementation in copyUSAsciiBytesToStr
+      final byte[] chars = (byte[]) stringValueFieldHandle.get(str);
       System.arraycopy(chars, 0, bytes, 0, str.length());
       // end copy
 
-      String result = copyUSAciiBytesToStr(str.length(), bytes);
+      String result = copyUSAsciiBytesToStr(str.length(), bytes);
       return str.equals(result);
     } catch (Throwable all) {
       return false;
     }
   }
 
-  static boolean testUSAsciiStrToBytesAlgorithm2(String str) {
-    try {
-      byte[] bytes = new byte[str.length()];
-
-      // copy of implementation in copyUSAciiBytesToStr
-      final char[] chars = (char[]) instance.getObject(str, 
stringValueFieldOffset);
-      int i = 0;
-      while (i < str.length()) {
-        bytes[i] = (byte) chars[i++];
-      }
-      // end copy
-
-      String result = copyUSAciiBytesToStr(str.length(), bytes);
-      return str.equals(result);
-    } catch (Throwable all) {
-      return false;
-    }
-  }
-
-  private static String copyUSAciiBytesToStr(int length, byte[] bytes) {
+  private static String copyUSAsciiBytesToStr(int length, byte[] bytes) {
     char[] resultChars = new char[length];
     int i = 0;
     while (i < length) {
@@ -130,14 +101,8 @@ public final class Unsafe {
 
   public static void copyUSAsciiStrToBytes(String str, byte[] bytes) {
     if (copyUSAsciiStrToBytesAlgorithm == 1) {
-      final byte[] chars = (byte[]) instance.getObject(str, 
stringValueFieldOffset);
+      final byte[] chars = (byte[]) stringValueFieldHandle.get(str);
       System.arraycopy(chars, 0, bytes, 0, str.length());
-    } else if (copyUSAsciiStrToBytesAlgorithm == 2) {
-      final char[] chars = (char[]) instance.getObject(str, 
stringValueFieldOffset);
-      int i = 0;
-      while (i < str.length()) {
-        bytes[i] = (byte) chars[i++];
-      }
     } else {
       byte[] strBytes = str.getBytes(StandardCharsets.US_ASCII);
       System.arraycopy(strBytes, 0, bytes, 0, str.length());
@@ -150,20 +115,7 @@ public final class Unsafe {
     int i = 0;
 
     if (copyUSAsciiStrToBytesAlgorithm == 1) {
-      final byte[] chars = (byte[]) instance.getObject(str, 
stringValueFieldOffset);
-      while (i < str.length()) {
-        long x = s0 ^ (long) chars[i++]; // Mix character into PRNG state
-        long y = s1;
-
-        // Xorshift128+ round
-        s0 = y;
-        x ^= x << 23;
-        y ^= y >>> 26;
-        x ^= x >>> 17;
-        s1 = x ^ y;
-      }
-    } else if (copyUSAsciiStrToBytesAlgorithm == 2) {
-      final char[] chars = (char[]) instance.getObject(str, 
stringValueFieldOffset);
+      final byte[] chars = (byte[]) stringValueFieldHandle.get(str);
       while (i < str.length()) {
         long x = s0 ^ (long) chars[i++]; // Mix character into PRNG state
         long y = s1;
diff --git a/project/PekkoBuild.scala b/project/PekkoBuild.scala
index f5cccef539..acc4b31e98 100644
--- a/project/PekkoBuild.scala
+++ b/project/PekkoBuild.scala
@@ -111,8 +111,7 @@ object PekkoBuild {
 
   private val jvmGCLogOptions: Seq[String] = Seq("-Xlog:gc*")
 
-  // -XDignore.symbol.file suppresses sun.misc.Unsafe warnings
-  final val DefaultJavacOptions = Seq("-encoding", "UTF-8", 
"-Xlint:unchecked", "-XDignore.symbol.file")
+  final val DefaultJavacOptions = Seq("-encoding", "UTF-8", "-Xlint:unchecked")
 
   lazy val defaultSettings: Seq[Setting[_]] = Def.settings(
     projectInfoVersion := (if (isSnapshot.value) "snapshot" else 
version.value),


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to