On Thu, 25 Jan 2024 14:48:16 GMT, Maurizio Cimadamore <mcimadam...@openjdk.org> 
wrote:

> I don't 100% buy the `MethodHandleImpl` analogy. In that case the check is 
> not simply used to save a branch, but to spare spinning of a completely new 
> lambda form.

Doing this to save a few intructions would not likely to worth the hassle 
outside the _really performance critical paths_, but even then it might be 
useful for hot JDK code. On larger examples, you can avoid memory accesses, 
allocations, etc. by coding up the constant-foldable path that you know 
compiler would not be able to extract when propagating constants through the 
generic code. For example, giving quantitative substance to my previous example:


diff --git a/src/java.base/share/classes/java/lang/Integer.java 
b/src/java.base/share/classes/java/lang/Integer.java
index 1c5b3c414ba..d50748c369e 100644
--- a/src/java.base/share/classes/java/lang/Integer.java
+++ b/src/java.base/share/classes/java/lang/Integer.java
@@ -28,4 +28,5 @@
 import jdk.internal.misc.CDS;
 import jdk.internal.misc.VM;
+import jdk.internal.vm.ConstantSupport;
 import jdk.internal.vm.annotation.ForceInline;
 import jdk.internal.vm.annotation.IntrinsicCandidate;
@@ -416,4 +417,7 @@ private static void formatUnsignedIntUTF16(int val, int 
shift, byte[] buf, int l
     }
 
+    @Stable
+    static final String[] TO_STRINGS = { "-1", "0", "1" };
+
     /**
      * Returns a {@code String} object representing the
@@ -428,4 +432,8 @@ private static void formatUnsignedIntUTF16(int val, int 
shift, byte[] buf, int l
     @IntrinsicCandidate
     public static String toString(int i) {
+        if (ConstantSupport.isCompileConstant(i) &&
+                (i >= -1) && (i <= 1)) {
+            return TO_STRINGS[i + 1];
+        }
         int size = stringSize(i);
         if (COMPACT_STRINGS) {
diff --git a/test/micro/org/openjdk/bench/java/lang/Integers.java 
b/test/micro/org/openjdk/bench/java/lang/Integers.java
index 43ceb5d18d2..28248593a73 100644
--- a/test/micro/org/openjdk/bench/java/lang/Integers.java
+++ b/test/micro/org/openjdk/bench/java/lang/Integers.java
@@ -91,4 +91,18 @@ public void decode(Blackhole bh) {
     }
 
+    @Benchmark
+    @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public String toStringConstYay() {
+        return Integer.toString(0);
+    }
+
+    int v = 0;
+
+    @Benchmark
+    @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public String toStringConstNope() {
+        return Integer.toString(v);
+    }
+
     /** Performs toString on small values, just a couple of digits. */
     @Benchmark



Benchmark                                      (size)  Mode  Cnt      Score     
Error   Units
Integers.toStringConstNope                        500  avgt   15      3,599 ?   
0,034   ns/op
Integers.toStringConstNope:gc.alloc.rate.norm     500  avgt   15     48,000 ?   
0,001    B/op
Integers.toStringConstNope:gc.time                500  avgt   15    223,000     
           ms
Integers.toStringConstYay                         500  avgt   15      0,568 ?   
0,046   ns/op
Integers.toStringConstYay:gc.alloc.rate.norm      500  avgt   15     ? 10??     
         B/op


Think about it as simplifying/avoiding the need for full compiler intrinsics. I 
could, in principle, do this by intrinsifying `Integer.toString` completely, 
check the same `isCon`, and then either construct the access to some String 
constant, or arrange the call to actual toString slow path. That would not be 
as simple as doing the similar thing in plain Java, with just a little of 
compiler support in form of `ConstantSupport`.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/17527#issuecomment-1910449450

Reply via email to