protected Expression writeChunk()

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;
  }