Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
4 changes: 4 additions & 0 deletions java/fory-core/src/main/java/org/apache/fory/Fory.java
Original file line number Diff line number Diff line change
Expand Up @@ -1712,6 +1712,10 @@ public boolean isCompatible() {
return config.getCompatibleMode() == CompatibleMode.COMPATIBLE;
}

public boolean isShareMeta() {
return shareMeta;
}

public boolean trackingRef() {
return refTracking;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import static org.apache.fory.type.TypeUtils.isPrimitive;
import static org.apache.fory.util.Preconditions.checkArgument;

import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -113,13 +114,16 @@
import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.CompatibleSerializer;
import org.apache.fory.serializer.EnumSerializer;
import org.apache.fory.serializer.FinalFieldReplaceResolveSerializer;
import org.apache.fory.serializer.ObjectSerializer;
import org.apache.fory.serializer.PrimitiveSerializers.LongSerializer;
import org.apache.fory.serializer.ReplaceResolveSerializer;
import org.apache.fory.serializer.Serializer;
import org.apache.fory.serializer.StringSerializer;
import org.apache.fory.serializer.collection.CollectionFlags;
import org.apache.fory.serializer.collection.CollectionLikeSerializer;
import org.apache.fory.serializer.collection.MapLikeSerializer;
import org.apache.fory.type.Descriptor;
import org.apache.fory.type.GenericType;
import org.apache.fory.type.TypeUtils;
import org.apache.fory.util.GraalvmSupport;
Expand Down Expand Up @@ -394,6 +398,104 @@ protected Expression serializeFor(
}
}

protected Expression serializeField(
Expression fieldValue, Expression buffer, Descriptor descriptor) {
TypeRef<?> typeRef = descriptor.getTypeRef();
boolean nullable = descriptor.isNullable();

if (needWriteRef(typeRef)) {
return new If(
not(writeRefOrNull(buffer, fieldValue)),
serializeForNotNullForField(fieldValue, buffer, typeRef, null, false));
} else {
// if typeToken is not final, ref tracking of subclass will be ignored too.
if (typeRef.isPrimitive()) {
return serializeForNotNullForField(fieldValue, buffer, typeRef, null, false);
}
if (nullable) {
Expression action =
new ListExpression(
new Invoke(buffer, "writeByte", Literal.ofByte(Fory.NOT_NULL_VALUE_FLAG)),
serializeForNotNullForField(fieldValue, buffer, typeRef, null, false));
return new If(
eqNull(fieldValue),
new Invoke(buffer, "writeByte", Literal.ofByte(Fory.NULL_FLAG)),
action);
} else {
return serializeForNotNullForField(fieldValue, buffer, typeRef, null, false);
}
}
}

private Expression serializeForNotNullForField(
Expression inputObject,
Expression buffer,
TypeRef<?> typeRef,
Expression serializer,
boolean generateNewMethod) {
Class<?> clz = getRawType(typeRef);
if (isPrimitive(clz) || isBoxed(clz)) {
return serializePrimitive(inputObject, buffer, clz);
} else {
if (clz == String.class) {
return fory.getStringSerializer().writeStringExpr(stringSerializerRef, buffer, inputObject);
}
Expression action;
if (useCollectionSerialization(typeRef)) {
action =
serializeForCollection(buffer, inputObject, typeRef, serializer, generateNewMethod);
} else if (useMapSerialization(typeRef)) {
action = serializeForMap(buffer, inputObject, typeRef, serializer, generateNewMethod);
} else {
action = serializeForNotNullObjectForField(inputObject, buffer, typeRef, serializer);
}
return action;
}
}

private Expression serializePrimitive(Expression inputObject, Expression buffer, Class<?> clz) {
// for primitive, inline call here to avoid java boxing, rather call corresponding serializer.
if (clz == byte.class || clz == Byte.class) {
return new Invoke(buffer, "writeByte", inputObject);
} else if (clz == boolean.class || clz == Boolean.class) {
return new Invoke(buffer, "writeBoolean", inputObject);
} else if (clz == char.class || clz == Character.class) {
return new Invoke(buffer, "writeChar", inputObject);
} else if (clz == short.class || clz == Short.class) {
return new Invoke(buffer, "writeInt16", inputObject);
} else if (clz == int.class || clz == Integer.class) {
String func = fory.compressInt() ? "writeVarInt32" : "writeInt32";
return new Invoke(buffer, func, inputObject);
} else if (clz == long.class || clz == Long.class) {
return LongSerializer.writeInt64(buffer, inputObject, fory.longEncoding(), true);
} else if (clz == float.class || clz == Float.class) {
return new Invoke(buffer, "writeFloat32", inputObject);
} else if (clz == double.class || clz == Double.class) {
return new Invoke(buffer, "writeFloat64", inputObject);
} else {
throw new IllegalStateException("impossible");
}
}

private Expression serializeForNotNullObjectForField(
Expression inputObject, Expression buffer, TypeRef<?> typeRef, Expression serializer) {
Class<?> clz = getRawType(typeRef);
if (serializer != null) {
return new Invoke(serializer, writeMethodName, buffer, inputObject);
}
if (isMonomorphic(clz)) {
// Use descriptor to get the appropriate serializer
serializer = getSerializerForField(clz);
return new Invoke(serializer, writeMethodName, buffer, inputObject);
} else {
return writeForNotNullNonFinalObject(inputObject, buffer, typeRef);
}
}

private Expression getSerializerForField(Class<?> cls) {
return getOrCreateSerializer(cls, true);
}

protected Expression serializeForNullable(
Expression inputObject, Expression buffer, TypeRef<?> typeRef, boolean nullable) {
return serializeForNullable(inputObject, buffer, typeRef, null, false, nullable);
Expand Down Expand Up @@ -463,27 +565,7 @@ private Expression serializeForNotNull(
boolean generateNewMethod) {
Class<?> clz = getRawType(typeRef);
if (isPrimitive(clz) || isBoxed(clz)) {
// for primitive, inline call here to avoid java boxing, rather call corresponding serializer.
if (clz == byte.class || clz == Byte.class) {
return new Invoke(buffer, "writeByte", inputObject);
} else if (clz == boolean.class || clz == Boolean.class) {
return new Invoke(buffer, "writeBoolean", inputObject);
} else if (clz == char.class || clz == Character.class) {
return new Invoke(buffer, "writeChar", inputObject);
} else if (clz == short.class || clz == Short.class) {
return new Invoke(buffer, "writeInt16", inputObject);
} else if (clz == int.class || clz == Integer.class) {
String func = fory.compressInt() ? "writeVarInt32" : "writeInt32";
return new Invoke(buffer, func, inputObject);
} else if (clz == long.class || clz == Long.class) {
return LongSerializer.writeInt64(buffer, inputObject, fory.longEncoding(), true);
} else if (clz == float.class || clz == Float.class) {
return new Invoke(buffer, "writeFloat32", inputObject);
} else if (clz == double.class || clz == Double.class) {
return new Invoke(buffer, "writeFloat64", inputObject);
} else {
throw new IllegalStateException("impossible");
}
return serializePrimitive(inputObject, buffer, clz);
} else {
if (clz == String.class) {
return fory.getStringSerializer().writeStringExpr(stringSerializerRef, buffer, inputObject);
Expand Down Expand Up @@ -599,12 +681,26 @@ protected Expression writeClassInfo(
* methods calls in most situations.
*/
protected Expression getOrCreateSerializer(Class<?> cls) {
return getOrCreateSerializer(cls, false);
}

private Expression getOrCreateSerializer(Class<?> cls, boolean isField) {
// Not need to check cls final, take collection writeSameTypeElements as an example.
// Preconditions.checkArgument(isMonomorphic(cls), cls);
Reference serializerRef = serializerMap.get(cls);
if (serializerRef == null) {
// potential recursive call for seq codec generation is handled in `getSerializerClass`.
Class<? extends Serializer> serializerClass = typeResolver(r -> r.getSerializerClass(cls));
boolean finalClassAsFieldCondition =
!fory.isShareMeta()
&& !fory.isCompatible()
&& isField
&& Modifier.isFinal(cls.getModifiers())
&& serializerClass == ReplaceResolveSerializer.class;
if (finalClassAsFieldCondition) {
serializerClass = FinalFieldReplaceResolveSerializer.class;
}

Preconditions.checkNotNull(serializerClass, "Unsupported for class " + cls);
if (!ReflectionUtils.isPublic(serializerClass)) {
// TODO(chaokunyang) add jdk17+ unexported class check.
Expand Down Expand Up @@ -640,12 +736,13 @@ protected Expression getOrCreateSerializer(Class<?> cls) {
&& !MapLikeSerializer.class.isAssignableFrom(serializerClass)) {
serializerClass = MapLikeSerializer.class;
}
TypeRef<? extends Serializer> serializerTypeRef = TypeRef.of(serializerClass);
Expression fieldTypeExpr = getClassExpr(cls);
String method =
finalClassAsFieldCondition ? "getRawSerializerFinalField" : "getRawSerializer";
// Don't invoke `Serializer.newSerializer` here, since it(ex. ObjectSerializer) may set itself
// as global serializer, which overwrite serializer updates in jit callback.
Expression newSerializerExpr =
inlineInvoke(typeResolverRef, "getRawSerializer", SERIALIZER_TYPE, fieldTypeExpr);
inlineInvoke(typeResolverRef, method, SERIALIZER_TYPE, fieldTypeExpr);
String name = ctx.newName(StringUtils.uncapitalize(serializerClass.getSimpleName()));
// It's ok it jit already finished and this method return false, in such cases
// `serializerClass` is already jit generated class.
Expand All @@ -656,6 +753,7 @@ protected Expression getOrCreateSerializer(Class<?> cls) {
false, ctx.type(Serializer.class), name, cast(newSerializerExpr, SERIALIZER_TYPE));
serializerRef = new Reference(name, SERIALIZER_TYPE, false);
} else {
TypeRef<? extends Serializer> serializerTypeRef = TypeRef.of(serializerClass);
ctx.addField(
true, ctx.type(serializerClass), name, cast(newSerializerExpr, serializerTypeRef));
serializerRef = fieldRef(name, serializerTypeRef);
Expand Down Expand Up @@ -1631,26 +1729,7 @@ protected Expression deserializeForNotNull(
Expression buffer, TypeRef<?> typeRef, Expression serializer, InvokeHint invokeHint) {
Class<?> cls = getRawType(typeRef);
if (isPrimitive(cls) || isBoxed(cls)) {
// for primitive, inline call here to avoid java boxing, rather call corresponding serializer.
if (cls == byte.class || cls == Byte.class) {
return new Invoke(buffer, "readByte", PRIMITIVE_BYTE_TYPE);
} else if (cls == boolean.class || cls == Boolean.class) {
return new Invoke(buffer, "readBoolean", PRIMITIVE_BOOLEAN_TYPE);
} else if (cls == char.class || cls == Character.class) {
return readChar(buffer);
} else if (cls == short.class || cls == Short.class) {
return readInt16(buffer);
} else if (cls == int.class || cls == Integer.class) {
return fory.compressInt() ? readVarInt32(buffer) : readInt32(buffer);
} else if (cls == long.class || cls == Long.class) {
return LongSerializer.readInt64(buffer, fory.longEncoding());
} else if (cls == float.class || cls == Float.class) {
return readFloat32(buffer);
} else if (cls == double.class || cls == Double.class) {
return readFloat64(buffer);
} else {
throw new IllegalStateException("impossible");
}
return deserializePrimitive(buffer, cls);
} else {
if (cls == String.class) {
return fory.getStringSerializer().readStringExpr(stringSerializerRef, buffer);
Expand All @@ -1677,6 +1756,83 @@ protected Expression deserializeForNotNull(
}
}

protected Expression deserializeField(
Expression buffer, Descriptor descriptor, Function<Expression, Expression> callback) {
TypeRef<?> typeRef = descriptor.getTypeRef();
boolean nullable = descriptor.isNullable();

if (typeResolver(r -> r.needToWriteRef(typeRef))) {
return readRef(buffer, callback, () -> deserializeForNotNullForField(buffer, typeRef, null));
} else {
if (typeRef.isPrimitive()) {
Expression value = deserializeForNotNullForField(buffer, typeRef, null);
// Should put value expr ahead to avoid generated code in wrong scope.
return new ListExpression(value, callback.apply(value));
}
return readNullable(
buffer,
typeRef,
callback,
() -> deserializeForNotNullForField(buffer, typeRef, null),
nullable);
}
}

private Expression deserializeForNotNullForField(
Expression buffer, TypeRef<?> typeRef, Expression serializer) {
Class<?> cls = getRawType(typeRef);
if (isPrimitive(cls) || isBoxed(cls)) {
return deserializePrimitive(buffer, cls);
} else {
if (cls == String.class) {
return fory.getStringSerializer().readStringExpr(stringSerializerRef, buffer);
}
Expression obj;
if (useCollectionSerialization(typeRef)) {
obj = deserializeForCollection(buffer, typeRef, serializer, null);
} else if (useMapSerialization(typeRef)) {
obj = deserializeForMap(buffer, typeRef, serializer, null);
} else {
if (serializer != null) {
return read(serializer, buffer, OBJECT_TYPE);
}
if (isMonomorphic(cls)) {
// Use descriptor to get the appropriate serializer
serializer = getSerializerForField(cls);
Class<?> returnType =
ReflectionUtils.getReturnType(getRawType(serializer.type()), readMethodName);
obj = read(serializer, buffer, TypeRef.of(returnType));
} else {
obj = readForNotNullNonFinal(buffer, typeRef, serializer);
}
}
return obj;
}
}

private Expression deserializePrimitive(Expression buffer, Class<?> cls) {
// for primitive, inline call here to avoid java boxing
if (cls == byte.class || cls == Byte.class) {
return new Invoke(buffer, "readByte", PRIMITIVE_BYTE_TYPE);
} else if (cls == boolean.class || cls == Boolean.class) {
return new Invoke(buffer, "readBoolean", PRIMITIVE_BOOLEAN_TYPE);
} else if (cls == char.class || cls == Character.class) {
return readChar(buffer);
} else if (cls == short.class || cls == Short.class) {
return readInt16(buffer);
} else if (cls == int.class || cls == Integer.class) {
return fory.compressInt() ? readVarInt32(buffer) : readInt32(buffer);
} else if (cls == long.class || cls == Long.class) {
return LongSerializer.readInt64(buffer, fory.longEncoding());
} else if (cls == float.class || cls == Float.class) {
return readFloat32(buffer);
} else if (cls == double.class || cls == Double.class) {
return readFloat64(buffer);
} else {
throw new IllegalStateException("impossible");
}
}

protected Expression read(Expression serializer, Expression buffer, TypeRef<?> returnType) {
Class<?> type = returnType.getRawType();
Expression read = new Invoke(serializer, readMethodName, returnType, buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,7 @@ private Expression serializeGroup(
// `bean` will be replaced by `Reference` to cut-off expr dependency.
Expression fieldValue = getFieldValue(bean, d);
walkPath.add(d.getDeclaringClass() + d.getName());
boolean nullable = d.isNullable();
Expression fieldExpr =
serializeForNullable(fieldValue, buffer, d.getTypeRef(), nullable);
Expression fieldExpr = serializeField(fieldValue, buffer, d);
walkPath.removeLast();
groupExpressions.add(fieldExpr);
}
Expand Down Expand Up @@ -555,17 +553,15 @@ protected Expression deserializeGroup(
for (Descriptor d : group) {
ExpressionVisitor.ExprHolder exprHolder = ExpressionVisitor.ExprHolder.of("bean", bean);
walkPath.add(d.getDeclaringClass() + d.getName());
boolean nullable = d.isNullable();
Expression action =
deserializeForNullable(
deserializeField(
buffer,
d.getTypeRef(),
d,
// `bean` will be replaced by `Reference` to cut-off expr
// dependency.
expr ->
setFieldValue(
exprHolder.get("bean"), d, tryInlineCast(expr, d.getTypeRef())),
nullable);
exprHolder.get("bean"), d, tryInlineCast(expr, d.getTypeRef())));
walkPath.removeLast();
groupExpressions.add(action);
}
Expand Down
Loading
Loading