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 d73c3d9f feat(java): reduce readInt/readVarInt code size for for jvm jit inline (#1469) d73c3d9f is described below commit d73c3d9f8c0c750ffe718a1553cd10c45e605c57 Author: Shawn Yang <shawn.ck.y...@gmail.com> AuthorDate: Sat Apr 6 18:59:32 2024 +0800 feat(java): reduce readInt/readVarInt code size for for jvm jit inline (#1469) This PR optimizes readVarInt/readInt performance by reduce code size of readVarInt for better jvm jit --- .../fury/builder/BaseObjectCodecBuilder.java | 3 +- .../java/org/apache/fury/builder/CodecBuilder.java | 16 ++- .../apache/fury/builder/ObjectCodecBuilder.java | 2 +- .../java/org/apache/fury/memory/MemoryBuffer.java | 118 ++++++++++++++++++++- 4 files changed, 133 insertions(+), 6 deletions(-) diff --git a/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java b/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java index 0b0b7594..a27abbab 100644 --- a/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java +++ b/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java @@ -1135,8 +1135,7 @@ public abstract class BaseObjectCodecBuilder extends CodecBuilder { } else if (cls == short.class || cls == Short.class) { return new Invoke(buffer, "readShort", PRIMITIVE_SHORT_TYPE); } else if (cls == int.class || cls == Integer.class) { - String func = fury.compressInt() ? "readVarInt" : "readInt"; - return new Invoke(buffer, func, PRIMITIVE_INT_TYPE); + return fury.compressInt() ? readVarInt(buffer) : readInt(buffer); } else if (cls == long.class || cls == Long.class) { return LongSerializer.readLong(buffer, fury.longEncoding()); } else if (cls == float.class || cls == Float.class) { 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 3ce014bc..457d41bf 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 @@ -595,7 +595,11 @@ public abstract class CodecBuilder { } protected Expression unsafeGetInt(Expression base, Expression pos) { - return new StaticInvoke(MemoryBuffer.class, "unsafeGetInt", PRIMITIVE_INT_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 expr; } protected Expression unsafeGetLong(Expression base, Expression pos) { @@ -610,4 +614,14 @@ public abstract class CodecBuilder { return new StaticInvoke( MemoryBuffer.class, "unsafeGetDouble", PRIMITIVE_DOUBLE_TYPE, base, pos); } + + protected Expression readInt(Expression buffer) { + String func = Platform.IS_LITTLE_ENDIAN ? "readIntOnLE" : "readIntOnBE"; + return new Invoke(buffer, func, PRIMITIVE_INT_TYPE); + } + + protected Expression readVarInt(Expression buffer) { + String func = Platform.IS_LITTLE_ENDIAN ? "readVarIntOnLE" : "readVarIntOnBE"; + return new Invoke(buffer, func, PRIMITIVE_INT_TYPE); + } } diff --git a/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java b/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java index 37365f9d..6731c313 100644 --- a/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java +++ b/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java @@ -695,7 +695,7 @@ public class ObjectCodecBuilder extends BaseObjectCodecBuilder { compressStarted = true; addIncReaderIndexExpr(groupExpressions, buffer, acc); } - fieldValue = new Invoke(buffer, "readVarInt", PRIMITIVE_INT_TYPE); + fieldValue = readVarInt(buffer); } } else if (clz == long.class) { if (!fury.compressLong()) { 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 6c933318..97285991 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 @@ -1223,9 +1223,94 @@ public final class MemoryBuffer { } /** Reads the 1-5 byte int part of a varint. */ + @CodegenInvoke public int readVarInt() { - int r = readPositiveVarInt(); - return (r >>> 1) ^ -(r & 1); + if (LITTLE_ENDIAN) { + return readVarIntOnLE(); + } else { + return readVarIntOnBE(); + } + } + + /** Reads the 1-5 byte as a varint on a little endian mache. */ + @CodegenInvoke + public int readVarIntOnLE() { + // noinspection Duplicates + int readIdx = readerIndex; + int result; + if (size - readIdx < 5) { + result = readPositiveVarIntSlow(); + } else { + long address = this.address; + // | 1bit + 7bits | 1bit + 7bits | 1bit + 7bits | 1bit + 7bits | + int fourByteValue = UNSAFE.getInt(heapMemory, address + readIdx); + // Duplicate and manual inline for performance. + // noinspection Duplicates + readIdx++; + result = fourByteValue & 0x7F; + if ((fourByteValue & 0x80) != 0) { + readIdx++; + // 0x3f80: 0b1111111 << 7 + result |= (fourByteValue >>> 1) & 0x3f80; + // 0x8000: 0b1 << 15 + if ((fourByteValue & 0x8000) != 0) { + readIdx++; + // 0x1fc000: 0b1111111 << 14 + result |= (fourByteValue >>> 2) & 0x1fc000; + // 0x800000: 0b1 << 23 + if ((fourByteValue & 0x800000) != 0) { + readIdx++; + // 0xfe00000: 0b1111111 << 21 + result |= (fourByteValue >>> 3) & 0xfe00000; + if ((fourByteValue & 0x80000000) != 0) { + result |= (UNSAFE.getByte(heapMemory, address + readIdx++) & 0x7F) << 28; + } + } + } + } + readerIndex = readIdx; + } + return (result >>> 1) ^ -(result & 1); + } + + /** Reads the 1-5 byte as a varint on a big endian mache. */ + @CodegenInvoke + public int readVarIntOnBE() { + // noinspection Duplicates + int readIdx = readerIndex; + int result; + if (size - readIdx < 5) { + result = readPositiveVarIntSlow(); + } else { + long address = this.address; + int fourByteValue = Integer.reverseBytes(UNSAFE.getInt(heapMemory, address + readIdx)); + // Duplicate and manual inline for performance. + // noinspection Duplicates + readIdx++; + result = fourByteValue & 0x7F; + if ((fourByteValue & 0x80) != 0) { + readIdx++; + // 0x3f80: 0b1111111 << 7 + result |= (fourByteValue >>> 1) & 0x3f80; + // 0x8000: 0b1 << 15 + if ((fourByteValue & 0x8000) != 0) { + readIdx++; + // 0x1fc000: 0b1111111 << 14 + result |= (fourByteValue >>> 2) & 0x1fc000; + // 0x800000: 0b1 << 23 + if ((fourByteValue & 0x800000) != 0) { + readIdx++; + // 0xfe00000: 0b1111111 << 21 + result |= (fourByteValue >>> 3) & 0xfe00000; + if ((fourByteValue & 0x80000000) != 0) { + result |= (UNSAFE.getByte(heapMemory, address + readIdx++) & 0x7F) << 28; + } + } + } + } + readerIndex = readIdx; + } + return (result >>> 1) ^ -(result & 1); } /** @@ -2008,6 +2093,35 @@ public final class MemoryBuffer { } } + @CodegenInvoke + public int readIntOnLE() { + 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 UNSAFE.getInt(heapMemory, address + readerIdx); + } + + // Reduce method body for better inline in the caller. + @CodegenInvoke + public int readIntOnBE() { + 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 Integer.reverseBytes(UNSAFE.getInt(heapMemory, address + readerIdx)); + } + public long readLong() { int readerIdx = readerIndex; // use subtract to avoid overflow --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@fury.apache.org For additional commands, e-mail: commits-h...@fury.apache.org