diff --git a/AyCode.Core.Serializers.Console/Program.cs b/AyCode.Core.Serializers.Console/Program.cs index 96cc02d..d4080e5 100644 --- a/AyCode.Core.Serializers.Console/Program.cs +++ b/AyCode.Core.Serializers.Console/Program.cs @@ -224,9 +224,9 @@ public static class Program // AcBinary variants new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.FastMode, SerializerAcBinaryFastMode), - new AcBinaryBenchmark(testData.Order, binaryFastModeNoSgenOption, SerializerAcBinaryFastNoSgen), + //new AcBinaryBenchmark(testData.Order, binaryFastModeNoSgenOption, SerializerAcBinaryFastNoSgen), new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.Default, SerializerAcBinaryDefault), - new AcBinaryBenchmark(testData.Order, binaryDefaultNoSgenOption, SerializerAcBinaryDefaultNoSgen), + //new AcBinaryBenchmark(testData.Order, binaryDefaultNoSgenOption, SerializerAcBinaryDefaultNoSgen), new AcBinaryBenchmark(testData.Order, AcBinarySerializerOptions.WithoutReferenceHandling, SerializerAcBinaryNoRef), new AcBinaryBenchmark(testData.Order, binaryNoInternOption, SerializerAcBinaryNoIntern), diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs index 5f2b5c2..432addf 100644 --- a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs +++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs @@ -723,6 +723,7 @@ public static partial class AcBinarySerializer WriteBytes(utf8Name); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteStringUtf8Internal(string value) { var byteCount = Utf8NoBom.GetByteCount(value); @@ -930,7 +931,7 @@ public static partial class AcBinarySerializer /// Cached type: ObjectWithTypeIndexRefFirst (71) + typeIndex + refCacheIndex /// /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + //[MethodImpl(MethodImplOptions.AggressiveInlining)] public void WritePolymorphicPrefix(Type runtimeType, int cachedObjectCacheIndex = -1) { var rtWrapper = GetWrapper(runtimeType); @@ -991,7 +992,7 @@ public static partial class AcBinarySerializer /// Első előfordulás: [propNameHash (4b)][propCount (VarUInt)][hash0 (4b)][hash1 (4b)]... /// Ismételt: [propNameHash (4b)] /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + //[MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteInlineMetadata(BinarySerializeTypeMetadata metadata, bool isFirstOccurrence) { WriteRaw(metadata.PropNameHash); diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs index d4a27d5..081a399 100644 --- a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs +++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.cs @@ -591,7 +591,7 @@ public static partial class AcBinarySerializer #endregion #region Value Writing - + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteValue(object? value, Type type, BinarySerializationContext context, int depth) where TOutput : struct, IBinaryOutputBase { @@ -1114,7 +1114,7 @@ public static partial class AcBinarySerializer /// /// String intern 2nd occurrence — cold path, just writes reference index. /// - [MethodImpl(MethodImplOptions.NoInlining)] + //[MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteStringInternRef(BinarySerializationContext context, int cacheMapIndex) where TOutput : struct, IBinaryOutputBase { @@ -1125,7 +1125,7 @@ public static partial class AcBinarySerializer /// /// Object ref 2nd occurrence — cold path, just writes reference index. /// - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteObjectRef(BinarySerializationContext context, int cacheMapIndex) where TOutput : struct, IBinaryOutputBase { @@ -1177,14 +1177,14 @@ public static partial class AcBinarySerializer context.WriteByte(BinaryTypeCode.Object); } - WriteObjectProperties(value, metadata, wrapper, context, depth, useMetaForType); + WriteObjectProperties(value, wrapper, context, depth, useMetaForType); } /// /// WriteObject variant with reference handling, no metadata. /// Cold path: only IId types with ref tracking enabled. /// - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteObjectWithRefHandling(object value, TypeMetadataWrapper wrapper, BinarySerializationContext context, int depth) where TOutput : struct, IBinaryOutputBase { @@ -1223,14 +1223,14 @@ public static partial class AcBinarySerializer context.WriteByte(BinaryTypeCode.Object); } - WriteObjectProperties(value, wrapper.Metadata, wrapper, context, depth, useMetaForType: false); + WriteObjectProperties(value, wrapper, context, depth, useMetaForType: false); } /// /// WriteObject variant with reference handling + metadata. /// Cold path: IId types with ref tracking + UseMetadata enabled. /// - [MethodImpl(MethodImplOptions.NoInlining)] + //[MethodImpl(MethodImplOptions.NoInlining)] private static void WriteObjectWithRefHandlingMeta(object value, TypeMetadataWrapper wrapper, BinarySerializationContext context, int depth) where TOutput : struct, IBinaryOutputBase { @@ -1264,20 +1264,18 @@ public static partial class AcBinarySerializer } context.WriteInlineMetadata(wrapper.Metadata, isFirstMetadataOccurrence); - WriteObjectProperties(value, wrapper.Metadata, wrapper, context, depth, useMetaForType: true); + WriteObjectProperties(value, wrapper, context, depth, useMetaForType: true); } /// /// Shared property writing loop — used by WriteObject, WriteObjectWithRefHandling, WriteObjectPolymorphic. /// - private static void WriteObjectProperties(object value, BinarySerializeTypeMetadata metadata, TypeMetadataWrapper wrapper, BinarySerializationContext context, int depth, bool useMetaForType) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteObjectProperties(object value, TypeMetadataWrapper wrapper, BinarySerializationContext context, int depth, bool useMetaForType) where TOutput : struct, IBinaryOutputBase { var nextDepth = depth + 1; - var properties = metadata.Properties; - var propCount = properties.Length; - var hasPropertyFilter = context.HasPropertyFilter; - + if (context.UseGeneratedCode) { var generatedWriter = wrapper.GeneratedWriter; @@ -1290,36 +1288,55 @@ public static partial class AcBinarySerializer if (!useMetaForType) { - for (var i = 0; i < propCount; i++) - { - var prop = properties[i]; - - if (prop.ExpectedTypeCode.HasValue) - { - WritePropertyMarkerless(value, prop, context); - } - else if (hasPropertyFilter && !context.ShouldSerializeProperty(value, prop)) - { - context.WriteByte(BinaryTypeCode.PropertySkip); - } - else - { - WritePropertyOrSkip(value, prop, wrapper, context, nextDepth); - } - } + WritePropertiesMarkerless(value, wrapper, context, nextDepth); } else { - for (var i = 0; i < propCount; i++) + WritePropertiesWithMeta(value, wrapper, context, nextDepth); + } + } + + private static void WritePropertiesWithMeta(object value, TypeMetadataWrapper wrapper, BinarySerializationContext context, int nextDepth) where TOutput : struct, IBinaryOutputBase + { + var properties = wrapper.Metadata.Properties; + var propCount = properties.Length; + var hasPropertyFilter = context.HasPropertyFilter; + + for (var i = 0; i < propCount; i++) + { + var prop = properties[i]; + + if (hasPropertyFilter && !context.ShouldSerializeProperty(value, prop)) { - var prop = properties[i]; + context.WriteByte(BinaryTypeCode.PropertySkip); + continue; + } - if (hasPropertyFilter && !context.ShouldSerializeProperty(value, prop)) - { - context.WriteByte(BinaryTypeCode.PropertySkip); - continue; - } + WritePropertyOrSkip(value, prop, wrapper, context, nextDepth); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WritePropertiesMarkerless(object value, TypeMetadataWrapper wrapper, BinarySerializationContext context, int nextDepth) where TOutput : struct, IBinaryOutputBase + { + var properties = wrapper.Metadata.Properties; + var propCount = properties.Length; + var hasPropertyFilter = context.HasPropertyFilter; + + for (var i = 0; i < propCount; i++) + { + var prop = properties[i]; + + if (prop.ExpectedTypeCode.HasValue) + { + WritePropertyMarkerless(value, prop, context); + } + else if (hasPropertyFilter && !context.ShouldSerializeProperty(value, prop)) + { + context.WriteByte(BinaryTypeCode.PropertySkip); + } + else + { WritePropertyOrSkip(value, prop, wrapper, context, nextDepth); } } @@ -1330,10 +1347,7 @@ public static partial class AcBinarySerializer /// Cold path: polymorphism is rare, NoInlining call overhead acceptable. /// [MethodImpl(MethodImplOptions.NoInlining)] - private static void WritePolymorphicMarker( - BinarySerializationContext context, - Type polyRuntimeType, - int cachedObjectCacheIndex) + private static void WritePolymorphicMarker(BinarySerializationContext context, Type polyRuntimeType, int cachedObjectCacheIndex) where TOutput : struct, IBinaryOutputBase { if (cachedObjectCacheIndex >= 0) @@ -1391,7 +1405,7 @@ public static partial class AcBinarySerializer // Poly marker (handles combined poly+ref) WritePolymorphicMarker(context, polyRuntimeType, cachedObjectCacheIndex); - WriteObjectProperties(value, metadata, wrapper, context, depth, false); + WriteObjectProperties(value, wrapper, context, depth, false); } /// @@ -1443,83 +1457,83 @@ public static partial class AcBinarySerializer /// /// Writes a property value using typed getters to avoid boxing. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WritePropertyValue(object obj, BinaryPropertyAccessor prop, BinarySerializationContext context, int depth) - where TOutput : struct, IBinaryOutputBase - { - switch (prop.AccessorType) - { - case PropertyAccessorType.Int32: - WriteInt32(prop.GetInt32(obj), context); - return; - case PropertyAccessorType.Int64: - WriteInt64(prop.GetInt64(obj), context); - return; - case PropertyAccessorType.Boolean: - context.WriteByte(prop.GetBoolean(obj) ? BinaryTypeCode.True : BinaryTypeCode.False); - return; - case PropertyAccessorType.Double: - WriteFloat64Unsafe(prop.GetDouble(obj), context); - return; - case PropertyAccessorType.Single: - WriteFloat32Unsafe(prop.GetSingle(obj), context); - return; - case PropertyAccessorType.Decimal: - WriteDecimalUnsafe(prop.GetDecimal(obj), context); - return; - case PropertyAccessorType.DateTime: - WriteDateTimeUnsafe(prop.GetDateTime(obj), context); - return; - case PropertyAccessorType.Byte: - context.WriteByte(BinaryTypeCode.UInt8); - context.WriteByte(prop.GetByte(obj)); - return; - case PropertyAccessorType.Int16: - WriteInt16Unsafe(prop.GetInt16(obj), context); - return; - case PropertyAccessorType.UInt16: - WriteUInt16Unsafe(prop.GetUInt16(obj), context); - return; - case PropertyAccessorType.UInt32: - WriteUInt32(prop.GetUInt32(obj), context); - return; - case PropertyAccessorType.UInt64: - WriteUInt64(prop.GetUInt64(obj), context); - return; - case PropertyAccessorType.Guid: - WriteGuidUnsafe(prop.GetGuid(obj), context); - return; - case PropertyAccessorType.Enum: - var enumValue = prop.GetEnumAsInt32(obj); - if (BinaryTypeCode.TryEncodeTinyInt(enumValue, out var tiny)) - { - context.WriteByte(BinaryTypeCode.Enum); - context.WriteByte(tiny); - } - else - { - context.WriteByte(BinaryTypeCode.Enum); - context.WriteByte(BinaryTypeCode.Int32); - context.WriteVarInt(enumValue); - } - return; - case PropertyAccessorType.String: - { - // Fast path: typed getter, no boxing, no Type.GetTypeCode() call - var strValue = prop.GetString(obj); - if (strValue != null) - WriteString(strValue, context); - else - context.WriteByte(BinaryTypeCode.Null); - return; - } - default: - // Fallback to object getter for reference types - var value = prop.GetValue(obj); - WriteValue(value, prop.PropertyType, context, depth); - return; - } - } + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //private static void WritePropertyValue(object obj, BinaryPropertyAccessor prop, BinarySerializationContext context, int depth) + // where TOutput : struct, IBinaryOutputBase + //{ + // switch (prop.AccessorType) + // { + // case PropertyAccessorType.Int32: + // WriteInt32(prop.GetInt32(obj), context); + // return; + // case PropertyAccessorType.Int64: + // WriteInt64(prop.GetInt64(obj), context); + // return; + // case PropertyAccessorType.Boolean: + // context.WriteByte(prop.GetBoolean(obj) ? BinaryTypeCode.True : BinaryTypeCode.False); + // return; + // case PropertyAccessorType.Double: + // WriteFloat64Unsafe(prop.GetDouble(obj), context); + // return; + // case PropertyAccessorType.Single: + // WriteFloat32Unsafe(prop.GetSingle(obj), context); + // return; + // case PropertyAccessorType.Decimal: + // WriteDecimalUnsafe(prop.GetDecimal(obj), context); + // return; + // case PropertyAccessorType.DateTime: + // WriteDateTimeUnsafe(prop.GetDateTime(obj), context); + // return; + // case PropertyAccessorType.Byte: + // context.WriteByte(BinaryTypeCode.UInt8); + // context.WriteByte(prop.GetByte(obj)); + // return; + // case PropertyAccessorType.Int16: + // WriteInt16Unsafe(prop.GetInt16(obj), context); + // return; + // case PropertyAccessorType.UInt16: + // WriteUInt16Unsafe(prop.GetUInt16(obj), context); + // return; + // case PropertyAccessorType.UInt32: + // WriteUInt32(prop.GetUInt32(obj), context); + // return; + // case PropertyAccessorType.UInt64: + // WriteUInt64(prop.GetUInt64(obj), context); + // return; + // case PropertyAccessorType.Guid: + // WriteGuidUnsafe(prop.GetGuid(obj), context); + // return; + // case PropertyAccessorType.Enum: + // var enumValue = prop.GetEnumAsInt32(obj); + // if (BinaryTypeCode.TryEncodeTinyInt(enumValue, out var tiny)) + // { + // context.WriteByte(BinaryTypeCode.Enum); + // context.WriteByte(tiny); + // } + // else + // { + // context.WriteByte(BinaryTypeCode.Enum); + // context.WriteByte(BinaryTypeCode.Int32); + // context.WriteVarInt(enumValue); + // } + // return; + // case PropertyAccessorType.String: + // { + // // Fast path: typed getter, no boxing, no Type.GetTypeCode() call + // var strValue = prop.GetString(obj); + // if (strValue != null) + // WriteString(strValue, context); + // else + // context.WriteByte(BinaryTypeCode.Null); + // return; + // } + // default: + // // Fallback to object getter for reference types + // var value = prop.GetValue(obj); + // WriteValue(value, prop.PropertyType, context, depth); + // return; + // } + //} /// /// Writes a property value OR a skip marker if the value is default/null.