This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-fury.git


The following commit(s) were added to refs/heads/main by this push:
     new 1d302ef1 feat(java): optimize read float/double for jvm jit inline 
(#1472)
1d302ef1 is described below

commit 1d302ef1112de7c684af65fd9b0589715129f91c
Author: Shawn Yang <shawn.ck.y...@gmail.com>
AuthorDate: Sat Apr 6 20:43:06 2024 +0800

    feat(java): optimize read float/double for jvm jit inline (#1472)
    
    - optimize read float jvm jit inline by separate little/big endian
    methods
    - optimize read double jvm jit inline by separate little/big endian
    methods
    - generate unsafe get float code online
    - generate unsafe get double code online
---
 .../java/org/apache/fury/builder/CodecBuilder.java |  36 +++--
 .../java/org/apache/fury/memory/MemoryBuffer.java  | 175 ++++++++-------------
 .../test/java/org/apache/fury/FuryTestBase.java    |   5 +
 .../org/apache/fury/memory/MemoryBufferTest.java   |   6 +-
 .../fury/serializer/PrimitiveSerializersTest.java  |  65 +++++++-
 5 files changed, 158 insertions(+), 129 deletions(-)

diff --git 
a/java/fury-core/src/main/java/org/apache/fury/builder/CodecBuilder.java 
b/java/fury-core/src/main/java/org/apache/fury/builder/CodecBuilder.java
index 746a698d..9c69757e 100644
--- a/java/fury-core/src/main/java/org/apache/fury/builder/CodecBuilder.java
+++ b/java/fury-core/src/main/java/org/apache/fury/builder/CodecBuilder.java
@@ -572,18 +572,13 @@ public abstract class CodecBuilder {
     return new StaticInvoke(MemoryBuffer.class, "unsafePutDouble", base, pos, 
value);
   }
 
-  /**
-   * Build unsafeGet operation.
-   *
-   * @see MemoryBuffer#unsafeGet(Object, long)
-   */
+  /** Build unsafeGet operation. */
   protected Expression unsafeGet(Expression base, Expression pos) {
-    return new StaticInvoke(MemoryBuffer.class, "unsafeGet", 
PRIMITIVE_BYTE_TYPE, base, pos);
+    return new StaticInvoke(Platform.class, "getByte", PRIMITIVE_BYTE_TYPE, 
base, pos);
   }
 
   protected Expression unsafeGetBoolean(Expression base, Expression pos) {
-    return new StaticInvoke(
-        MemoryBuffer.class, "unsafeGetBoolean", PRIMITIVE_BOOLEAN_TYPE, base, 
pos);
+    return new StaticInvoke(Platform.class, "getBoolean", 
PRIMITIVE_BOOLEAN_TYPE, base, pos);
   }
 
   protected Expression unsafeGetChar(Expression base, Expression pos) {
@@ -614,18 +609,25 @@ public abstract class CodecBuilder {
   protected Expression unsafeGetLong(Expression base, Expression pos) {
     StaticInvoke expr = new StaticInvoke(Platform.class, "getLong", 
PRIMITIVE_LONG_TYPE, base, pos);
     if (!Platform.IS_LITTLE_ENDIAN) {
-      expr = new StaticInvoke(Long.class, "reverseBytes", PRIMITIVE_INT_TYPE, 
expr.inline());
+      expr = new StaticInvoke(Long.class, "reverseBytes", PRIMITIVE_LONG_TYPE, 
expr.inline());
     }
     return expr;
   }
 
   protected Expression unsafeGetFloat(Expression base, Expression pos) {
-    return new StaticInvoke(MemoryBuffer.class, "unsafeGetFloat", 
PRIMITIVE_FLOAT_TYPE, base, pos);
+    StaticInvoke expr = new StaticInvoke(Platform.class, "getInt", 
PRIMITIVE_INT_TYPE, base, pos);
+    if (!Platform.IS_LITTLE_ENDIAN) {
+      expr = new StaticInvoke(Integer.class, "reverseBytes", 
PRIMITIVE_INT_TYPE, expr.inline());
+    }
+    return new StaticInvoke(Float.class, "intBitsToFloat", 
PRIMITIVE_FLOAT_TYPE, expr.inline());
   }
 
   protected Expression unsafeGetDouble(Expression base, Expression pos) {
-    return new StaticInvoke(
-        MemoryBuffer.class, "unsafeGetDouble", PRIMITIVE_DOUBLE_TYPE, base, 
pos);
+    StaticInvoke expr = new StaticInvoke(Platform.class, "getLong", 
PRIMITIVE_LONG_TYPE, base, pos);
+    if (!Platform.IS_LITTLE_ENDIAN) {
+      expr = new StaticInvoke(Long.class, "reverseBytes", PRIMITIVE_LONG_TYPE, 
expr.inline());
+    }
+    return new StaticInvoke(Double.class, "longBitsToDouble", 
PRIMITIVE_DOUBLE_TYPE, expr.inline());
   }
 
   protected Expression readChar(Expression buffer) {
@@ -655,4 +657,14 @@ public abstract class CodecBuilder {
   public static String readLongFunc() {
     return Platform.IS_LITTLE_ENDIAN ? "readLongOnLE" : "readLongOnBE";
   }
+
+  protected Expression readFloat(Expression buffer) {
+    String func = Platform.IS_LITTLE_ENDIAN ? "readFloatOnLE" : 
"readFloatOnBE";
+    return new Invoke(buffer, func, PRIMITIVE_FLOAT_TYPE);
+  }
+
+  protected Expression readDouble(Expression buffer) {
+    String func = Platform.IS_LITTLE_ENDIAN ? "readDoubleOnLE" : 
"readDoubleOnBE";
+    return new Invoke(buffer, func, PRIMITIVE_DOUBLE_TYPE);
+  }
 }
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/memory/MemoryBuffer.java 
b/java/fury-core/src/main/java/org/apache/fury/memory/MemoryBuffer.java
index 155b8df6..025ceb28 100644
--- a/java/fury-core/src/main/java/org/apache/fury/memory/MemoryBuffer.java
+++ b/java/fury-core/src/main/java/org/apache/fury/memory/MemoryBuffer.java
@@ -252,10 +252,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public static byte unsafeGet(Object o, long offset) {
-    return UNSAFE.getByte(o, offset);
-  }
-
   public byte unsafeGet(int index) {
     final long pos = address + index;
     return UNSAFE.getByte(heapMemory, pos);
@@ -444,15 +440,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public static boolean unsafeGetBoolean(Object o, long offset) {
-    return UNSAFE.getBoolean(o, offset);
-  }
-
-  public boolean unsafeGetBoolean(int index) {
-    final long pos = address + index;
-    return UNSAFE.getByte(heapMemory, pos) != 0;
-  }
-
   public boolean getBoolean(int index) {
     return get(index) != 0;
   }
@@ -475,14 +462,6 @@ public final class MemoryBuffer {
     return UNSAFE.getChar(heapMemory, pos);
   }
 
-  public char getCharB(int index) {
-    if (LITTLE_ENDIAN) {
-      return Character.reverseBytes(getCharN(index));
-    } else {
-      return getCharN(index);
-    }
-  }
-
   public char getChar(int index) {
     if (LITTLE_ENDIAN) {
       return getCharN(index);
@@ -548,12 +527,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public void putShortN(int index, short value) {
-    final long pos = address + index;
-    checkPosition(index, pos, 2);
-    UNSAFE.putShort(heapMemory, pos, value);
-  }
-
   public void putShort(int index, short value) {
     final long pos = address + index;
     checkPosition(index, pos, 2);
@@ -590,12 +563,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public int getIntN(int index) {
-    final long pos = address + index;
-    checkPosition(index, pos, 4);
-    return UNSAFE.getInt(heapMemory, pos);
-  }
-
   public int getInt(int index) {
     final long pos = address + index;
     checkPosition(index, pos, 4);
@@ -606,12 +573,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public void putIntN(int index, int value) {
-    final long pos = address + index;
-    checkPosition(index, pos, 4);
-    UNSAFE.putInt(heapMemory, pos, value);
-  }
-
   public void putInt(int index, int value) {
     final long pos = address + index;
     checkPosition(index, pos, 4);
@@ -622,11 +583,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public int unsafeGetIntN(int index) {
-    final long pos = address + index;
-    return UNSAFE.getInt(heapMemory, pos);
-  }
-
   public int unsafeGetInt(int index) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -644,11 +600,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public void unsafePutIntN(int index, int value) {
-    final long pos = address + index;
-    UNSAFE.putInt(heapMemory, pos, value);
-  }
-
   public void unsafePutInt(int index, int value) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -666,12 +617,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public long getLongN(int index) {
-    final long pos = address + index;
-    checkPosition(index, pos, 8);
-    return UNSAFE.getLong(heapMemory, pos);
-  }
-
   public long getLong(int index) {
     final long pos = address + index;
     checkPosition(index, pos, 8);
@@ -716,11 +661,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public long unsafeGetLongN(int index) {
-    final long pos = address + index;
-    return UNSAFE.getLong(heapMemory, pos);
-  }
-
   public long unsafeGetLong(int index) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -738,11 +678,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public void unsafePutLongN(int index, long value) {
-    final long pos = address + index;
-    UNSAFE.putLong(heapMemory, pos, value);
-  }
-
   public void unsafePutLong(int index, long value) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -760,10 +695,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public float getFloatN(int index) {
-    return Float.intBitsToFloat(getIntN(index));
-  }
-
   public float getFloat(int index) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -773,10 +704,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public void putFloatN(int index, float value) {
-    putIntN(index, Float.floatToRawIntBits(value));
-  }
-
   public void putFloat(int index, float value) {
     final long pos = address + index;
     checkPosition(index, pos, 4);
@@ -787,10 +714,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public float unsafeGetFloatN(int index) {
-    return Float.intBitsToFloat(unsafeGetIntN(index));
-  }
-
   public float unsafeGetFloat(int index) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -800,18 +723,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public static float unsafeGetFloat(Object o, long pos) {
-    if (LITTLE_ENDIAN) {
-      return Float.intBitsToFloat(UNSAFE.getInt(o, pos));
-    } else {
-      return Float.intBitsToFloat(Integer.reverseBytes(UNSAFE.getInt(o, pos)));
-    }
-  }
-
-  public void unsafePutFloatN(int index, float value) {
-    unsafePutIntN(index, Float.floatToRawIntBits(value));
-  }
-
   public void unsafePutFloat(int index, float value) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -829,10 +740,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public double getDoubleN(int index) {
-    return Double.longBitsToDouble(getLongN(index));
-  }
-
   public double getDouble(int index) {
     final long pos = address + index;
     checkPosition(index, pos, 8);
@@ -843,10 +750,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public void putDoubleN(int index, double value) {
-    putLongN(index, Double.doubleToRawLongBits(value));
-  }
-
   public void putDouble(int index, double value) {
     final long pos = address + index;
     checkPosition(index, pos, 8);
@@ -857,10 +760,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public double unsafeGetDoubleN(int index) {
-    return Double.longBitsToDouble(unsafeGetLongN(index));
-  }
-
   public double unsafeGetDouble(int index) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -870,18 +769,6 @@ public final class MemoryBuffer {
     }
   }
 
-  public static double unsafeGetDouble(Object o, long pos) {
-    if (LITTLE_ENDIAN) {
-      return Double.longBitsToDouble(UNSAFE.getLong(o, pos));
-    } else {
-      return Double.longBitsToDouble(Long.reverseBytes(UNSAFE.getLong(o, 
pos)));
-    }
-  }
-
-  public void unsafePutDoubleN(int index, double value) {
-    unsafePutLongN(index, Double.doubleToRawLongBits(value));
-  }
-
   public void unsafePutDouble(int index, double value) {
     final long pos = address + index;
     if (LITTLE_ENDIAN) {
@@ -2318,6 +2205,37 @@ public final class MemoryBuffer {
     }
   }
 
+  // Reduce method body for better inline in the caller.
+  @CodegenInvoke
+  public float readFloatOnLE() {
+    int readerIdx = readerIndex;
+    // use subtract to avoid overflow
+    int remaining = size - readerIdx;
+    if (remaining < 4) {
+      throw new IndexOutOfBoundsException(
+          String.format(
+              "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, 
4, size, this));
+    }
+    readerIndex = readerIdx + 4;
+    return Float.intBitsToFloat(UNSAFE.getInt(heapMemory, address + 
readerIdx));
+  }
+
+  // Reduce method body for better inline in the caller.
+  @CodegenInvoke
+  public float readFloatOnBE() {
+    int readerIdx = readerIndex;
+    // use subtract to avoid overflow
+    int remaining = size - readerIdx;
+    if (remaining < 4) {
+      throw new IndexOutOfBoundsException(
+          String.format(
+              "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, 
4, size, this));
+    }
+    readerIndex = readerIdx + 4;
+    return Float.intBitsToFloat(
+        Integer.reverseBytes(UNSAFE.getInt(heapMemory, address + readerIdx)));
+  }
+
   public double readDouble() {
     int readerIdx = readerIndex;
     // use subtract to avoid overflow
@@ -2335,6 +2253,37 @@ public final class MemoryBuffer {
     }
   }
 
+  // Reduce method body for better inline in the caller.
+  @CodegenInvoke
+  public double readDoubleOnLE() {
+    int readerIdx = readerIndex;
+    // use subtract to avoid overflow
+    int remaining = size - readerIdx;
+    if (remaining < 8) {
+      throw new IndexOutOfBoundsException(
+          String.format(
+              "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, 
8, size, this));
+    }
+    readerIndex = readerIdx + 8;
+    return Double.longBitsToDouble(UNSAFE.getLong(heapMemory, address + 
readerIdx));
+  }
+
+  // Reduce method body for better inline in the caller.
+  @CodegenInvoke
+  public double readDoubleOnBE() {
+    int readerIdx = readerIndex;
+    // use subtract to avoid overflow
+    int remaining = size - readerIdx;
+    if (remaining < 8) {
+      throw new IndexOutOfBoundsException(
+          String.format(
+              "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, 
8, size, this));
+    }
+    readerIndex = readerIdx + 8;
+    return Double.longBitsToDouble(
+        Long.reverseBytes(UNSAFE.getLong(heapMemory, address + readerIdx)));
+  }
+
   public byte[] readBytes(int length) {
     int readerIdx = readerIndex;
     // use subtract to avoid overflow
diff --git a/java/fury-core/src/test/java/org/apache/fury/FuryTestBase.java 
b/java/fury-core/src/test/java/org/apache/fury/FuryTestBase.java
index acf841fa..af379661 100644
--- a/java/fury-core/src/test/java/org/apache/fury/FuryTestBase.java
+++ b/java/fury-core/src/test/java/org/apache/fury/FuryTestBase.java
@@ -95,6 +95,11 @@ public abstract class FuryTestBase {
     return new Object[][] {{false}, {true}};
   }
 
+  @DataProvider
+  public static Object[][] compressNumberAndCodeGen() {
+    return new Object[][] {{false, false}, {true, false}, {false, true}, 
{true, true}};
+  }
+
   @DataProvider
   public static Object[][] refTrackingAndCompressNumber() {
     return new Object[][] {{false, false}, {true, false}, {false, true}, 
{true, true}};
diff --git 
a/java/fury-core/src/test/java/org/apache/fury/memory/MemoryBufferTest.java 
b/java/fury-core/src/test/java/org/apache/fury/memory/MemoryBufferTest.java
index 78fa41ba..89d8b821 100644
--- a/java/fury-core/src/test/java/org/apache/fury/memory/MemoryBufferTest.java
+++ b/java/fury-core/src/test/java/org/apache/fury/memory/MemoryBufferTest.java
@@ -75,9 +75,9 @@ public class MemoryBufferTest {
       MemoryBuffer.unsafePutDouble(heapMemory, pos, -1);
       pos += 8;
       MemoryBuffer.unsafePutFloat(heapMemory, pos, -1);
-      assertEquals(MemoryBuffer.unsafeGetFloat(heapMemory, pos), -1);
+      assertEquals(buffer.unsafeGetFloat((int) (pos - 
Platform.BYTE_ARRAY_OFFSET)), -1);
       pos -= 8;
-      assertEquals(MemoryBuffer.unsafeGetDouble(heapMemory, pos), -1);
+      assertEquals(buffer.unsafeGetDouble((int) (pos - 
Platform.BYTE_ARRAY_OFFSET)), -1);
       pos -= 8;
       assertEquals(MemoryBuffer.unsafeGetLong(heapMemory, pos), 
Long.MAX_VALUE);
       pos -= 4;
@@ -85,7 +85,7 @@ public class MemoryBufferTest {
       pos -= 2;
       assertEquals(buffer.getShort((int) (pos - Platform.BYTE_ARRAY_OFFSET)), 
Short.MAX_VALUE);
       pos -= 1;
-      assertEquals(MemoryBuffer.unsafeGet(heapMemory, pos), Byte.MIN_VALUE);
+      assertEquals(buffer.get((int) (pos - Platform.BYTE_ARRAY_OFFSET)), 
Byte.MIN_VALUE);
     }
     {
       MemoryBuffer buffer = MemoryUtils.buffer(1024);
diff --git 
a/java/fury-core/src/test/java/org/apache/fury/serializer/PrimitiveSerializersTest.java
 
b/java/fury-core/src/test/java/org/apache/fury/serializer/PrimitiveSerializersTest.java
index e7d56cf3..42a4b3b3 100644
--- 
a/java/fury-core/src/test/java/org/apache/fury/serializer/PrimitiveSerializersTest.java
+++ 
b/java/fury-core/src/test/java/org/apache/fury/serializer/PrimitiveSerializersTest.java
@@ -21,12 +21,17 @@ package org.apache.fury.serializer;
 
 import static org.testng.Assert.*;
 
+import lombok.AllArgsConstructor;
+import lombok.Data;
 import org.apache.fury.Fury;
+import org.apache.fury.FuryTestBase;
+import org.apache.fury.config.FuryBuilder;
 import org.apache.fury.config.Language;
+import org.apache.fury.config.LongEncoding;
 import org.apache.fury.memory.MemoryBuffer;
 import org.testng.annotations.Test;
 
-public class PrimitiveSerializersTest {
+public class PrimitiveSerializersTest extends FuryTestBase {
   @Test
   public void testUint8Serializer() {
     Fury fury = 
Fury.builder().withLanguage(Language.XLANG).requireClassRegistration(false).build();
@@ -54,4 +59,62 @@ public class PrimitiveSerializersTest {
     assertThrows(IllegalArgumentException.class, () -> 
serializer.xwrite(buffer, -1));
     assertThrows(IllegalArgumentException.class, () -> 
serializer.xwrite(buffer, 65536));
   }
+
+  @Data
+  @AllArgsConstructor
+  public static class PrimitiveStruct {
+    byte byte1;
+    byte byte2;
+    char char1;
+    char char2;
+    short short1;
+    short short2;
+    int int1;
+    int int2;
+    long long1;
+    long long2;
+    float float1;
+    float float2;
+    double double1;
+    double double2;
+  }
+
+  @Test(dataProvider = "compressNumberAndCodeGen")
+  public void testPrimitiveStruct(boolean compressNumber, boolean codegen) {
+    PrimitiveStruct struct =
+        new PrimitiveStruct(
+            Byte.MIN_VALUE,
+            Byte.MIN_VALUE,
+            Character.MIN_VALUE,
+            Character.MIN_VALUE,
+            Short.MIN_VALUE,
+            Short.MIN_VALUE,
+            Integer.MIN_VALUE,
+            Integer.MIN_VALUE,
+            Long.MIN_VALUE,
+            Long.MIN_VALUE,
+            Float.MIN_VALUE,
+            Float.MIN_VALUE,
+            Double.MIN_VALUE,
+            Double.MIN_VALUE);
+    if (compressNumber) {
+      FuryBuilder builder =
+          Fury.builder()
+              .withLanguage(Language.JAVA)
+              .withCodegen(codegen)
+              .requireClassRegistration(false);
+      serDeCheck(
+          
builder.withNumberCompressed(true).withLongCompressed(LongEncoding.PVL).build(),
 struct);
+      serDeCheck(
+          
builder.withNumberCompressed(true).withLongCompressed(LongEncoding.SLI).build(),
 struct);
+    } else {
+      Fury fury =
+          Fury.builder()
+              .withLanguage(Language.JAVA)
+              .withCodegen(codegen)
+              .requireClassRegistration(false)
+              .build();
+      serDeCheck(fury, struct);
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@fury.apache.org
For additional commands, e-mail: commits-h...@fury.apache.org

Reply via email to