in java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java [1143:1364]
protected Expression writeChunk(
Expression buffer,
Expression entry,
Expression iterator,
TypeRef<?> keyType,
TypeRef<?> valueType) {
ListExpression expressions = new ListExpression();
Expression key = invoke(entry, "getKey", "key", keyType);
Expression value = invoke(entry, "getValue", "value", valueType);
boolean keyMonomorphic = isMonomorphic(keyType);
boolean valueMonomorphic = isMonomorphic(valueType);
Class<?> keyTypeRawType = keyType.getRawType();
Class<?> valueTypeRawType = valueType.getRawType();
Expression keyTypeExpr =
keyMonomorphic
? getClassExpr(keyTypeRawType)
: new Invoke(key, "getClass", "keyType", CLASS_TYPE);
Expression valueTypeExpr =
valueMonomorphic
? getClassExpr(valueTypeRawType)
: new Invoke(value, "getClass", "valueType", CLASS_TYPE);
Expression writePlaceHolder = new Invoke(buffer, "writeInt16", Literal.ofShort((short) -1));
Expression chunkSizeOffset =
subtract(
inlineInvoke(buffer, "writerIndex", PRIMITIVE_INT_TYPE), ofInt(1), "chunkSizeOffset");
expressions.add(
key,
value,
keyTypeExpr,
valueTypeExpr,
writePlaceHolder,
chunkSizeOffset,
writePlaceHolder,
chunkSizeOffset);
Expression chunkHeader;
Expression keySerializer, valueSerializer;
boolean trackingKeyRef = visitFury(fury -> fury.getClassResolver().needToWriteRef(keyType));
boolean trackingValueRef = visitFury(fury -> fury.getClassResolver().needToWriteRef(valueType));
Expression keyWriteRef = Literal.ofBoolean(trackingKeyRef);
Expression valueWriteRef = Literal.ofBoolean(trackingValueRef);
boolean inline = keyMonomorphic && valueMonomorphic;
if (keyMonomorphic && valueMonomorphic) {
keySerializer = getOrCreateSerializer(keyTypeRawType);
valueSerializer = getOrCreateSerializer(valueTypeRawType);
int header = KEY_DECL_TYPE | VALUE_DECL_TYPE;
if (trackingKeyRef) {
header |= TRACKING_KEY_REF;
}
if (trackingValueRef) {
header |= TRACKING_VALUE_REF;
}
chunkHeader = ofInt(header);
expressions.add(chunkHeader);
} else if (keyMonomorphic) {
int header = KEY_DECL_TYPE;
if (trackingKeyRef) {
header |= TRACKING_KEY_REF;
}
keySerializer = getOrCreateSerializer(keyTypeRawType);
walkPath.add("value:" + valueType);
valueSerializer = writeClassInfo(buffer, valueTypeExpr, valueTypeRawType, true);
walkPath.removeLast();
chunkHeader = ExpressionUtils.ofInt("chunkHeader", header);
expressions.add(chunkHeader);
if (trackingValueRef) {
// value type may be subclass and not track ref.
valueWriteRef =
new Invoke(valueSerializer, "needToWriteRef", "valueWriteRef", PRIMITIVE_BOOLEAN_TYPE);
expressions.add(
new If(
valueWriteRef,
new Assign(chunkHeader, bitor(chunkHeader, ofInt(TRACKING_VALUE_REF)))));
}
} else if (valueMonomorphic) {
walkPath.add("key:" + keyType);
keySerializer = writeClassInfo(buffer, keyTypeExpr, keyTypeRawType, true);
walkPath.removeLast();
valueSerializer = getOrCreateSerializer(valueTypeRawType);
int header = VALUE_DECL_TYPE;
if (trackingValueRef) {
header |= TRACKING_VALUE_REF;
}
chunkHeader = ExpressionUtils.ofInt("chunkHeader", header);
expressions.add(chunkHeader);
if (trackingKeyRef) {
// key type may be subclass and not track ref.
keyWriteRef =
new Invoke(keySerializer, "needToWriteRef", "keyWriteRef", PRIMITIVE_BOOLEAN_TYPE);
expressions.add(
new If(
keyWriteRef, new Assign(chunkHeader, bitor(chunkHeader, ofInt(TRACKING_KEY_REF)))));
}
} else {
walkPath.add("key:" + keyType);
keySerializer = writeClassInfo(buffer, keyTypeExpr, keyTypeRawType, true);
walkPath.removeLast();
walkPath.add("value:" + valueType);
valueSerializer = writeClassInfo(buffer, valueTypeExpr, valueTypeRawType, true);
walkPath.removeLast();
chunkHeader = ExpressionUtils.ofInt("chunkHeader", 0);
expressions.add(chunkHeader);
if (trackingKeyRef) {
// key type may be subclass and not track ref.
keyWriteRef =
new Invoke(keySerializer, "needToWriteRef", "keyWriteRef", PRIMITIVE_BOOLEAN_TYPE);
expressions.add(
new If(
keyWriteRef, new Assign(chunkHeader, bitor(chunkHeader, ofInt(TRACKING_KEY_REF)))));
}
if (trackingValueRef) {
// key type may be subclass and not track ref.
valueWriteRef =
new Invoke(valueSerializer, "needToWriteRef", "valueWriteRef", PRIMITIVE_BOOLEAN_TYPE);
expressions.add(
new If(
valueWriteRef,
new Assign(chunkHeader, bitor(chunkHeader, ofInt(TRACKING_VALUE_REF)))));
}
}
Expression chunkSize = ExpressionUtils.ofInt("chunkSize", 0);
expressions.add(
keySerializer,
valueSerializer,
keyWriteRef,
valueWriteRef,
new Invoke(buffer, "putByte", subtract(chunkSizeOffset, ofInt(1)), chunkHeader),
chunkSize);
Expression keyWriteRefExpr = keyWriteRef;
Expression valueWriteRefExpr = valueWriteRef;
While writeLoop =
new While(
Literal.ofBoolean(true),
() -> {
Expression breakCondition;
if (keyMonomorphic && valueMonomorphic) {
breakCondition = or(eqNull(key), eqNull(value));
} else if (keyMonomorphic) {
breakCondition =
or(
eqNull(key),
eqNull(value),
neq(inlineInvoke(value, "getClass", CLASS_TYPE), valueTypeExpr));
} else if (valueMonomorphic) {
breakCondition =
or(
eqNull(key),
eqNull(value),
neq(inlineInvoke(key, "getClass", CLASS_TYPE), keyTypeExpr));
} else {
breakCondition =
or(
eqNull(key),
eqNull(value),
neq(inlineInvoke(key, "getClass", CLASS_TYPE), keyTypeExpr),
neq(inlineInvoke(value, "getClass", CLASS_TYPE), valueTypeExpr));
}
Expression writeKey = serializeForNotNull(key, buffer, keyType, keySerializer);
if (trackingKeyRef) {
writeKey =
new If(
or(
not(keyWriteRefExpr),
not(
inlineInvoke(
refResolverRef,
"writeRefOrNull",
PRIMITIVE_BOOLEAN_TYPE,
buffer,
key))),
writeKey);
}
Expression writeValue =
serializeForNotNull(value, buffer, valueType, valueSerializer);
if (trackingValueRef) {
writeValue =
new If(
or(
not(valueWriteRefExpr),
not(
inlineInvoke(
refResolverRef,
"writeRefOrNull",
PRIMITIVE_BOOLEAN_TYPE,
buffer,
value))),
writeValue);
}
return new ListExpression(
new If(breakCondition, new Break()),
writeKey,
writeValue,
new Assign(chunkSize, add(chunkSize, ofInt(1))),
new If(
inlineInvoke(iterator, "hasNext", PRIMITIVE_BOOLEAN_TYPE),
new ListExpression(
new Assign(
entry,
cast(inlineInvoke(iterator, "next", OBJECT_TYPE), MAP_ENTRY_TYPE)),
new Assign(
key,
tryInlineCast(inlineInvoke(entry, "getKey", OBJECT_TYPE), keyType)),
new Assign(value, invokeInline(entry, "getValue", valueType))),
list(new Assign(entry, new Literal(null, MAP_ENTRY_TYPE)), new Break())),
new If(eq(chunkSize, ofInt(MAX_CHUNK_SIZE)), new Break()));
});
expressions.add(writeLoop, new Invoke(buffer, "putByte", chunkSizeOffset, chunkSize));
if (!inline) {
expressions.add(new Return(entry));
// method too big, spilt it into a new method.
// Generate similar signature as `AbstractMapSerializer.writeJavaChunk`(
// MemoryBuffer buffer,
// Entry<Object, Object> entry,
// Iterator<Entry<Object, Object>> iterator,
// Serializer keySerializer,
// Serializer valueSerializer
// )
Set<Expression> params = ofHashSet(buffer, entry, iterator);
return invokeGenerated(ctx, params, expressions, "writeChunk", false);
}
return expressions;
}