Skip to content

Commit

Permalink
feat(java): reduce code size of read long to optimize jvm jit inline (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
chaokunyang authored Apr 6, 2024
1 parent d73c3d9 commit f6e9c73
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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(
Expand All @@ -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) {
Expand Down
227 changes: 190 additions & 37 deletions java/fury-core/src/main/java/org/apache/fury/memory/MemoryBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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));
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit f6e9c73

Please sign in to comment.