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