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 f6e9c732 feat(java): reduce code size of read long to optimize jvm jit 
inline (#1470)
f6e9c732 is described below

commit f6e9c732a0701c7f59444282ff33c234d8548e5d
Author: Shawn Yang <shawn.ck.y...@gmail.com>
AuthorDate: Sat Apr 6 19:29:42 2024 +0800

    feat(java): reduce code size of read long to optimize jvm jit inline (#1470)
    
    This PR reduced code size of read long for jvm jit inline:
    - Reduced readVarLong code size by separating little/big endian
    - Reduced readLong code size by separating little/big endian
    - Reduced unsafeGetLong code size by separating little/big endian and
    generate online
---
 .../java/org/apache/fury/builder/CodecBuilder.java |  14 +-
 .../fury/builder/CompatibleCodecBuilder.java       |  10 +-
 .../java/org/apache/fury/memory/MemoryBuffer.java  | 227 +++++++++++++++++----
 .../fury/serializer/PrimitiveSerializers.java      |   7 +-
 4 files changed, 213 insertions(+), 45 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 457d41bf..121c6ecb 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
@@ -603,7 +603,11 @@ public abstract class CodecBuilder {
   }
 
   protected Expression unsafeGetLong(Expression base, Expression pos) {
-    return new StaticInvoke(MemoryBuffer.class, "unsafeGetLong", 
PRIMITIVE_LONG_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_INT_TYPE, 
expr.inline());
+    }
+    return expr;
   }
 
   protected Expression unsafeGetFloat(Expression base, Expression pos) {
@@ -624,4 +628,12 @@ public abstract class CodecBuilder {
     String func = Platform.IS_LITTLE_ENDIAN ? "readVarIntOnLE" : 
"readVarIntOnBE";
     return new Invoke(buffer, func, PRIMITIVE_INT_TYPE);
   }
+
+  protected Expression readLong(Expression buffer) {
+    return new Invoke(buffer, readLongFunc(), PRIMITIVE_LONG_TYPE);
+  }
+
+  public static String readLongFunc() {
+    return Platform.IS_LITTLE_ENDIAN ? "readLongOnLE" : "readLongOnBE";
+  }
 }
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/builder/CompatibleCodecBuilder.java
 
b/java/fury-core/src/main/java/org/apache/fury/builder/CompatibleCodecBuilder.java
index 50117db0..02be7621 100644
--- 
a/java/fury-core/src/main/java/org/apache/fury/builder/CompatibleCodecBuilder.java
+++ 
b/java/fury-core/src/main/java/org/apache/fury/builder/CompatibleCodecBuilder.java
@@ -718,7 +718,7 @@ public class CompatibleCodecBuilder extends 
BaseObjectCodecBuilder {
                 setFieldValue(bean, descriptor, tryInlineCast(expr, 
descriptor.getTypeToken())));
     return new ListExpression(
         deserializeAction,
-        new Assign(partFieldInfo, inlineInvoke(buffer, "readLong", 
PRIMITIVE_LONG_TYPE)));
+        new Assign(partFieldInfo, inlineInvoke(buffer, readLongFunc(), 
PRIMITIVE_LONG_TYPE)));
   }
 
   private void readSeparateTypesHashFields(
@@ -866,7 +866,7 @@ public class CompatibleCodecBuilder extends 
BaseObjectCodecBuilder {
             fieldInfo.getEncodedFieldInfo());
     return new ListExpression(
         new Expression.ForceEvaluate(readAction),
-        new Assign(partFieldInfo, inlineInvoke(buffer, "readLong", 
PRIMITIVE_LONG_TYPE)));
+        new Assign(partFieldInfo, inlineInvoke(buffer, readLongFunc(), 
PRIMITIVE_LONG_TYPE)));
   }
 
   protected Expression getFinalClassInfo(Class<?> cls) {
@@ -939,7 +939,8 @@ public class CompatibleCodecBuilder extends 
BaseObjectCodecBuilder {
                             partFieldInfo),
                         endTagLiteral),
                     returnEndTag ? new Return(endTagLiteral) : new 
Return(bean)),
-                new Assign(partFieldInfo, inlineInvoke(buffer, "readLong", 
PRIMITIVE_LONG_TYPE))));
+                new Assign(
+                    partFieldInfo, inlineInvoke(buffer, readLongFunc(), 
PRIMITIVE_LONG_TYPE))));
   }
 
   private Expression skipField8End(
@@ -958,7 +959,8 @@ public class CompatibleCodecBuilder extends 
BaseObjectCodecBuilder {
                             partFieldInfo),
                         endTagLiteral),
                     new Return(bean)),
-                new Assign(partFieldInfo, inlineInvoke(buffer, "readLong", 
PRIMITIVE_LONG_TYPE))));
+                new Assign(
+                    partFieldInfo, inlineInvoke(buffer, readLongFunc(), 
PRIMITIVE_LONG_TYPE))));
   }
 
   private Comparator isEmbedType(Expression partFieldInfo, int flagBits, byte 
flagValue) {
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 97285991..105fcd8c 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
@@ -1768,6 +1768,114 @@ public final class MemoryBuffer {
     return ((result >>> 1) ^ -(result & 1));
   }
 
+  public long readVarLongOnLE() {
+    int readIdx = readerIndex;
+    long result;
+    if (size - readIdx < 9) {
+      result = readPositiveVarLongSlow();
+    } else {
+      long address = this.address;
+      long value = Long.reverseBytes(UNSAFE.getLong(heapMemory, address + 
readIdx));
+      // Duplicate and manual inline for performance.
+      // noinspection Duplicates
+      readIdx++;
+      result = value & 0x7F;
+      if ((value & 0x80) != 0) {
+        readIdx++;
+        // 0x3f80: 0b1111111 << 7
+        result |= (value >>> 1) & 0x3f80;
+        // 0x8000: 0b1 << 15
+        if ((value & 0x8000) != 0) {
+          readIdx++;
+          // 0x1fc000: 0b1111111 << 14
+          result |= (value >>> 2) & 0x1fc000;
+          // 0x800000: 0b1 << 23
+          if ((value & 0x800000) != 0) {
+            readIdx++;
+            // 0xfe00000: 0b1111111 << 21
+            result |= (value >>> 3) & 0xfe00000;
+            if ((value & 0x80000000L) != 0) {
+              readIdx++;
+              result |= (value >>> 4) & 0x7f0000000L;
+              if ((value & 0x8000000000L) != 0) {
+                readIdx++;
+                result |= (value >>> 5) & 0x3f800000000L;
+                if ((value & 0x800000000000L) != 0) {
+                  readIdx++;
+                  result |= (value >>> 6) & 0x1fc0000000000L;
+                  if ((value & 0x80000000000000L) != 0) {
+                    readIdx++;
+                    result |= (value >>> 7) & 0xfe000000000000L;
+                    if ((value & 0x8000000000000000L) != 0) {
+                      long b = UNSAFE.getByte(heapMemory, address + readIdx++);
+                      result |= b << 56;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      readerIndex = readIdx;
+    }
+    return ((result >>> 1) ^ -(result & 1));
+  }
+
+  public long readVarLongOnBE() {
+    int readIdx = readerIndex;
+    long result;
+    if (size - readIdx < 9) {
+      result = readPositiveVarLongSlow();
+    } else {
+      long address = this.address;
+      long value = UNSAFE.getLong(heapMemory, address + readIdx);
+      // Duplicate and manual inline for performance.
+      // noinspection Duplicates
+      readIdx++;
+      result = value & 0x7F;
+      if ((value & 0x80) != 0) {
+        readIdx++;
+        // 0x3f80: 0b1111111 << 7
+        result |= (value >>> 1) & 0x3f80;
+        // 0x8000: 0b1 << 15
+        if ((value & 0x8000) != 0) {
+          readIdx++;
+          // 0x1fc000: 0b1111111 << 14
+          result |= (value >>> 2) & 0x1fc000;
+          // 0x800000: 0b1 << 23
+          if ((value & 0x800000) != 0) {
+            readIdx++;
+            // 0xfe00000: 0b1111111 << 21
+            result |= (value >>> 3) & 0xfe00000;
+            if ((value & 0x80000000L) != 0) {
+              readIdx++;
+              result |= (value >>> 4) & 0x7f0000000L;
+              if ((value & 0x8000000000L) != 0) {
+                readIdx++;
+                result |= (value >>> 5) & 0x3f800000000L;
+                if ((value & 0x800000000000L) != 0) {
+                  readIdx++;
+                  result |= (value >>> 6) & 0x1fc0000000000L;
+                  if ((value & 0x80000000000000L) != 0) {
+                    readIdx++;
+                    result |= (value >>> 7) & 0xfe000000000000L;
+                    if ((value & 0x8000000000000000L) != 0) {
+                      long b = UNSAFE.getByte(heapMemory, address + readIdx++);
+                      result |= b << 56;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      readerIndex = readIdx;
+    }
+    return ((result >>> 1) ^ -(result & 1));
+  }
+
   /** Reads the 1-9 byte int part of a non-negative var long. */
   public long readPositiveVarLong() {
     int readIdx = readerIndex;
@@ -1906,42 +2014,6 @@ public final class MemoryBuffer {
     }
   }
 
-  /** Read fury SLI(Small Long as Int) encoded long. */
-  public long readSliLong() {
-    final int readIdx = readerIndex;
-    final long pos = address + readIdx;
-    final int size = this.size;
-    final byte[] heapMemory = this.heapMemory;
-    if (BoundsChecking.BOUNDS_CHECKING_ENABLED && readIdx > size - 4) {
-      throwIndexOutOfBoundsException(readIdx, size, 4);
-    }
-    if (LITTLE_ENDIAN) {
-      int i = UNSAFE.getInt(heapMemory, pos);
-      if ((i & 0b1) != 0b1) {
-        readerIndex = readIdx + 4;
-        return i >> 1;
-      } else {
-        if (BoundsChecking.BOUNDS_CHECKING_ENABLED && readIdx > size - 9) {
-          throwIndexOutOfBoundsException(readIdx, size, 9);
-        }
-        readerIndex = readIdx + 9;
-        return UNSAFE.getLong(heapMemory, pos + 1);
-      }
-    } else {
-      int i = Integer.reverseBytes(UNSAFE.getInt(heapMemory, pos));
-      if ((i & 0b1) != 0b1) {
-        readerIndex = readIdx + 4;
-        return i >> 1;
-      } else {
-        if (BoundsChecking.BOUNDS_CHECKING_ENABLED && readIdx > size - 9) {
-          throwIndexOutOfBoundsException(readIdx, size, 9);
-        }
-        readerIndex = readIdx + 9;
-        return Long.reverseBytes(UNSAFE.getLong(heapMemory, pos + 1));
-      }
-    }
-  }
-
   private void throwIndexOutOfBoundsException(int readIdx, int size, int need) 
{
     throw new IndexOutOfBoundsException(
         String.format(
@@ -2125,7 +2197,8 @@ public final class MemoryBuffer {
   public long readLong() {
     int readerIdx = readerIndex;
     // use subtract to avoid overflow
-    if (BoundsChecking.BOUNDS_CHECKING_ENABLED && readerIdx > size - 8) {
+    int remaining = size - readerIdx;
+    if (remaining < 8) {
       throw new IndexOutOfBoundsException(
           String.format(
               "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, 
8, size, this));
@@ -2139,6 +2212,86 @@ public final class MemoryBuffer {
     }
   }
 
+  // Reduce method body for better inline in the caller.
+  @CodegenInvoke
+  public long readLongOnLE() {
+    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 UNSAFE.getLong(heapMemory, address + readerIdx);
+  }
+
+  // Reduce method body for better inline in the caller.
+  @CodegenInvoke
+  public long readLongOnBE() {
+    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 Long.reverseBytes(UNSAFE.getLong(heapMemory, address + readerIdx));
+  }
+
+  /** Read fury SLI(Small Long as Int) encoded long. */
+  public long readSliLong() {
+    if (LITTLE_ENDIAN) {
+      return readSliLongOnLE();
+    } else {
+      return readSliLongOnBE();
+    }
+  }
+
+  @CodegenInvoke
+  public long readSliLongOnLE() {
+    // Duplicate and manual inline for performance.
+    // noinspection Duplicates
+    final int readIdx = readerIndex;
+    int diff = size - readIdx;
+    if (diff < 4) {
+      throwIndexOutOfBoundsException(readIdx, size, 4 - diff);
+    }
+    int i = UNSAFE.getInt(heapMemory, address + readIdx);
+    if ((i & 0b1) != 0b1) {
+      readerIndex = readIdx + 4;
+      return i >> 1;
+    }
+    if (diff < 9) {
+      throwIndexOutOfBoundsException(readIdx, size, 9 - diff);
+    }
+    readerIndex = readIdx + 9;
+    return UNSAFE.getLong(heapMemory, address + readIdx + 1);
+  }
+
+  @CodegenInvoke
+  public long readSliLongOnBE() {
+    // noinspection Duplicates
+    final int readIdx = readerIndex;
+    int diff = size - readIdx;
+    if (diff < 4) {
+      throwIndexOutOfBoundsException(readIdx, size, 4 - diff);
+    }
+    int i = Integer.reverseBytes(UNSAFE.getInt(heapMemory, address + readIdx));
+    if ((i & 0b1) != 0b1) {
+      readerIndex = readIdx + 4;
+      return i >> 1;
+    }
+    if (diff < 9) {
+      throwIndexOutOfBoundsException(readIdx, size, 9 - diff);
+    }
+    readerIndex = readIdx + 9;
+    return Long.reverseBytes(UNSAFE.getLong(heapMemory, address + readIdx + 
1));
+  }
+
   public float readFloat() {
     int readerIdx = readerIndex;
     // use subtract to avoid overflow
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/serializer/PrimitiveSerializers.java
 
b/java/fury-core/src/main/java/org/apache/fury/serializer/PrimitiveSerializers.java
index 4622e0d6..7cace7dc 100644
--- 
a/java/fury-core/src/main/java/org/apache/fury/serializer/PrimitiveSerializers.java
+++ 
b/java/fury-core/src/main/java/org/apache/fury/serializer/PrimitiveSerializers.java
@@ -27,6 +27,7 @@ import org.apache.fury.codegen.Expression.Invoke;
 import org.apache.fury.config.LongEncoding;
 import org.apache.fury.memory.MemoryBuffer;
 import org.apache.fury.type.Type;
+import org.apache.fury.util.Platform;
 import org.apache.fury.util.Preconditions;
 
 /** Serializers for java primitive types. */
@@ -268,11 +269,11 @@ public class PrimitiveSerializers {
     public static String readLongFunc(LongEncoding longEncoding) {
       switch (longEncoding) {
         case LE_RAW_BYTES:
-          return "readLong";
+          return Platform.IS_LITTLE_ENDIAN ? "readLongOnLE" : "readLongOnBE";
         case SLI:
-          return "readSliLong";
+          return Platform.IS_LITTLE_ENDIAN ? "readSliLongOnLE" : 
"readSliLongOnBE";
         case PVL:
-          return "readVarLong";
+          return Platform.IS_LITTLE_ENDIAN ? "readVarLongOnLE" : 
"readVarLongOnBE";
         default:
           throw new UnsupportedOperationException("Unsupported long encoding " 
+ longEncoding);
       }


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

Reply via email to