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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]