Skip to content

Commit

Permalink
[Java] Fix private record JIT (#1004)
Browse files Browse the repository at this point in the history
* fix private record jit

* add codegen param

* lint code
  • Loading branch information
chaokunyang authored Oct 11, 2023
1 parent 037239e commit b9e1b19
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,16 @@ public void testPrivateRecords(boolean codegen) {
Assert.assertEquals(fury.deserialize(bytes), o2);
}
}

@Test(dataProvider = "codegen")
public void testPrivateRecord(boolean codegen) {
Fury fury = Fury.builder().withCodegen(codegen).build();
fury.register(PrivateRecord.class);
byte[] serialized = fury.serialize(new PrivateRecord("foo")); // fails
Object deserialized = fury.deserialize(serialized);
System.out.println(deserialized);
}

private record PrivateRecord(String foo) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
import io.fury.serializer.Serializer;
import io.fury.serializer.Serializers;
import io.fury.serializer.StringSerializer;
import io.fury.type.FinalObjectTypeStub;
import io.fury.type.TypeUtils;
import io.fury.util.ReflectionUtils;
import io.fury.util.StringUtils;
Expand Down Expand Up @@ -946,40 +945,6 @@ private Expression writeContainerElement(
return new ListExpression(elem, write);
}

protected Expression tryInlineCast(Expression expression, TypeToken<?> targetType) {
return tryCastIfPublic(expression, targetType, true);
}

protected Expression tryCastIfPublic(Expression expression, TypeToken<?> targetType) {
return tryCastIfPublic(expression, targetType, false);
}

protected Expression tryCastIfPublic(
Expression expression, TypeToken<?> targetType, boolean inline) {
if (getRawType(targetType) == FinalObjectTypeStub.class) {
// final field doesn't exist in this class, skip cast.
return expression;
}
if (inline) {
if (ReflectionUtils.isPublic(targetType)
&& !expression.type().wrap().isSubtypeOf(targetType.wrap())) {
return new Cast(expression, targetType);
} else {
return expression;
}
}
return tryCastIfPublic(expression, targetType, "castedValue");
}

protected Expression tryCastIfPublic(
Expression expression, TypeToken<?> targetType, String valuePrefix) {
if (ReflectionUtils.isPublic(targetType)
&& !expression.type().wrap().isSubtypeOf(targetType.wrap())) {
return new Cast(expression, targetType, valuePrefix);
}
return expression;
}

/**
* Return an expression to write a map to <code>buffer</code>. This expression can have better
* efficiency for final key/value type. For final key/value type, it doesn't have to write class
Expand Down
45 changes: 44 additions & 1 deletion java/fury-core/src/main/java/io/fury/builder/CodecBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.fury.builder;

import static io.fury.codegen.Expression.Invoke.inlineInvoke;
import static io.fury.type.TypeUtils.OBJECT_ARRAY_TYPE;
import static io.fury.type.TypeUtils.OBJECT_TYPE;
import static io.fury.type.TypeUtils.PRIMITIVE_BOOLEAN_TYPE;
Expand Down Expand Up @@ -45,6 +46,7 @@
import io.fury.resolver.ClassInfo;
import io.fury.resolver.ClassInfoHolder;
import io.fury.type.Descriptor;
import io.fury.type.FinalObjectTypeStub;
import io.fury.util.Platform;
import io.fury.util.ReflectionUtils;
import io.fury.util.StringUtils;
Expand Down Expand Up @@ -115,6 +117,40 @@ public CodecBuilder(CodegenContext ctx, TypeToken<?> beanType) {
/** Returns an expression that serialize java bean of type {@link CodecBuilder#beanClass}. */
public abstract Expression buildEncodeExpression();

protected Expression tryInlineCast(Expression expression, TypeToken<?> targetType) {
return tryCastIfPublic(expression, targetType, true);
}

protected Expression tryCastIfPublic(Expression expression, TypeToken<?> targetType) {
return tryCastIfPublic(expression, targetType, false);
}

protected Expression tryCastIfPublic(
Expression expression, TypeToken<?> targetType, boolean inline) {
if (getRawType(targetType) == FinalObjectTypeStub.class) {
// final field doesn't exist in this class, skip cast.
return expression;
}
if (inline) {
if (ReflectionUtils.isPublic(targetType)
&& !expression.type().wrap().isSubtypeOf(targetType.wrap())) {
return new Cast(expression, targetType);
} else {
return expression;
}
}
return tryCastIfPublic(expression, targetType, "castedValue");
}

protected Expression tryCastIfPublic(
Expression expression, TypeToken<?> targetType, String valuePrefix) {
if (ReflectionUtils.isPublic(targetType)
&& !expression.type().wrap().isSubtypeOf(targetType.wrap())) {
return new Cast(expression, targetType, valuePrefix);
}
return expression;
}

// left null check in sub class encode method to reduce data dependence.
private final boolean fieldNullable = false;

Expand Down Expand Up @@ -212,7 +248,14 @@ private Expression getRecordFieldValue(Expression inputBeanExpr, Descriptor desc
ref = new Reference(key, getterType);
fieldMap.put(key, ref);
}
return new Invoke(ref, methodInfo.f1, fieldType, fieldNullable, inputBeanExpr);
if (!fieldType.isPrimitive()) {
Expression v = inlineInvoke(ref, methodInfo.f1, OBJECT_TYPE, fieldNullable, inputBeanExpr);
TypeToken<?> publicSuperType =
ReflectionUtils.getPublicSuperType(descriptor.getTypeToken());
return new Cast(v, publicSuperType, fieldName);
} else {
return new Invoke(ref, methodInfo.f1, fieldType, fieldNullable, inputBeanExpr);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,11 @@ public static <T> T makeFunction(Lookup lookup, MethodHandle handle, Class<T> fu
}

public static Tuple2<Class<?>, String> getterMethodInfo(Class<?> type) {
return methodMap.get(type);
Tuple2<Class<?>, String> info = methodMap.get(type);
if (info == null) {
return Tuple2.of(Function.class, "apply");
}
return info;
}

public static Object makeGetterFunction(
Expand Down

0 comments on commit b9e1b19

Please sign in to comment.