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 457d41bf67..121c6ecb7f 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 @@ protected Expression unsafeGetInt(Expression base, Expression pos) { } 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 @@ protected Expression readVarInt(Expression buffer) { 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 50117db0a3..02be76218b 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 @@ private Expression readEmbedTypes8Field( 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 @@ private Expression readObjectField( 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 @@ private Expression skipDataBy8Until( 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 @@ private Expression skipField8End( 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 972859911f..105fcd8c90 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 long readVarLong() { 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 int unsafeWriteSliLong(long value) { } } - /** 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 int readIntOnBE() { 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 long readLong() { } } + // 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 4622e0d693..7cace7dcf0 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.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 static Expression readLong(Expression buffer, LongEncoding longEncoding) 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); }