Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(java): reduce code size of read long to optimize jvm jit inline #1470

Merged
merged 6 commits into from
Apr 6, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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 @@ -2125,7 +2233,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 +2248,36 @@ 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));
}

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 ? "readSliLongLE" : "readSliLongBE";
case PVL:
return "readVarLong";
return Platform.IS_LITTLE_ENDIAN ? "readVarLongOnLE" : "readVarLongOnBE";
default:
throw new UnsupportedOperationException("Unsupported long encoding " + longEncoding);
}
Expand Down
Loading