[LOADED_DOCS: 2 files, no new loads]
Refactor AcBinary SGen: switch dispatch + new TODOs Refactored the AcBinary source generator to use switch-based dispatch for deserialization, replacing sequential if-else chains for improved performance and clarity. Updated comments to document the new logic. Added several new feature and refactor TODOs in BINARY_TODO.md, including Memory/Span overloads, async Stream serialization modes, non-generic Type-based APIs, attribute-driven polymorphism, and a thread-safety fix for serializer options. Each TODO includes rationale and acceptance criteria.
This commit is contained in:
parent
3b45de6de3
commit
329c9c2928
|
|
@ -1930,35 +1930,47 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
// Ref tracking possible — Object/ObjectRefFirst/ObjectRef/FixObj dispatch
|
||||
// Inline: parent creates instance + handles cache registration
|
||||
sb.AppendLine($"{i}if ({tc} == BinaryTypeCode.Object)");
|
||||
// Ref tracking possible — switch on tc (Object / ObjectRefFirst / [Null] / ObjectRef / <Object).
|
||||
// The 4 known TypeCode constants are emitted as switch cases — the JIT compiles them as a
|
||||
// jump-table for O(1) dispatch (vs the previous if-else chain's sequential ==-compares).
|
||||
// The polymorphic FixObj range-check (tc < Object) goes into the default branch — runtime
|
||||
// bridge path is rare on a typical SGen graph, so default fall-through is acceptable.
|
||||
// Inline: parent creates instance + handles cache registration.
|
||||
sb.AppendLine($"{i}switch ({tc})");
|
||||
sb.AppendLine($"{i}{{");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.Object:");
|
||||
sb.AppendLine($"{i} {{");
|
||||
sb.AppendLine($"{i} var rc_{p.Name} = new {p.TypeNameForTypeof}();");
|
||||
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(rc_{p.Name}, context, {nd});");
|
||||
sb.AppendLine($"{i} {a} = rc_{p.Name};");
|
||||
sb.AppendLine($"{i}}}");
|
||||
sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.ObjectRefFirst)");
|
||||
sb.AppendLine($"{i}{{");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i} }}");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.ObjectRefFirst:");
|
||||
sb.AppendLine($"{i} {{");
|
||||
sb.AppendLine($"{i} var ci_{p.Name} = (int)context.ReadVarUInt();");
|
||||
sb.AppendLine($"{i} var rc_{p.Name} = new {p.TypeNameForTypeof}();");
|
||||
sb.AppendLine($"{i} context.RegisterInternedValueAt(ci_{p.Name}, rc_{p.Name});");
|
||||
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(rc_{p.Name}, context, {nd});");
|
||||
sb.AppendLine($"{i} {a} = rc_{p.Name};");
|
||||
sb.AppendLine($"{i}}}");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i} }}");
|
||||
if (p.IsNullable)
|
||||
sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.Null) {{ /* null */ }}");
|
||||
sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.ObjectRef)");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.Null: break;");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.ObjectRef:");
|
||||
sb.AppendLine($"{i} {a} = {cast}context.GetInternedObject((int)context.ReadVarUInt())!;");
|
||||
// FixObj slot (0..SlotCount-1): same type via FixObj marker (non-meta, non-ref mode)
|
||||
sb.AppendLine($"{i} break;");
|
||||
// FixObj slot (0..SlotCount-1): same type via FixObj marker (non-meta, non-ref mode).
|
||||
// Populate slot cache to keep _nextRuntimeSlot in sync with the serializer.
|
||||
sb.AppendLine($"{i}else if ({tc} < BinaryTypeCode.Object)");
|
||||
sb.AppendLine($"{i}{{");
|
||||
sb.AppendLine($"{i} default:");
|
||||
sb.AppendLine($"{i} if ({tc} < BinaryTypeCode.Object)");
|
||||
sb.AppendLine($"{i} {{");
|
||||
sb.AppendLine($"{i} context.GetWrapper(typeof({p.TypeNameForTypeof}), {tc});");
|
||||
sb.AppendLine($"{i} if ({tc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {tc} + 1;");
|
||||
sb.AppendLine($"{i} var rc_{p.Name} = new {p.TypeNameForTypeof}();");
|
||||
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(rc_{p.Name}, context, {nd});");
|
||||
sb.AppendLine($"{i} {a} = rc_{p.Name};");
|
||||
sb.AppendLine($"{i} }}");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i}}}");
|
||||
}
|
||||
}
|
||||
|
|
@ -2286,36 +2298,48 @@ public class AcBinarySourceGenerator : IIncrementalGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
// Object hot path first, then ref markers, then FixObj — inline ReadProperties
|
||||
sb.AppendLine($"{i}if ({etc} == BinaryTypeCode.Object)");
|
||||
// Switch on etc (Object / ObjectRefFirst / Null / ObjectRef / <Object). The JIT emits the
|
||||
// 4 known TypeCode constants as a jump-table (O(1) dispatch); the polymorphic FixObj
|
||||
// range-check (etc < Object) goes into the default branch. Object hot-path stays first.
|
||||
sb.AppendLine($"{i}switch ({etc})");
|
||||
sb.AppendLine($"{i}{{");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.Object:");
|
||||
sb.AppendLine($"{i} {{");
|
||||
sb.AppendLine($"{i} var re_{propSuffix} = new {elemTypeName}();");
|
||||
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(re_{propSuffix}, context, nd_{propSuffix});");
|
||||
sb.AppendLine($"{i} {assignExpr}");
|
||||
sb.AppendLine($"{i}}}");
|
||||
sb.AppendLine($"{i}else if ({etc} == BinaryTypeCode.ObjectRefFirst)");
|
||||
sb.AppendLine($"{i}{{");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i} }}");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.ObjectRefFirst:");
|
||||
sb.AppendLine($"{i} {{");
|
||||
sb.AppendLine($"{i} var ci_{propSuffix} = (int)context.ReadVarUInt();");
|
||||
sb.AppendLine($"{i} var re_{propSuffix} = new {elemTypeName}();");
|
||||
sb.AppendLine($"{i} context.RegisterInternedValueAt(ci_{propSuffix}, re_{propSuffix});");
|
||||
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(re_{propSuffix}, context, nd_{propSuffix});");
|
||||
sb.AppendLine($"{i} {assignExpr}");
|
||||
sb.AppendLine($"{i}}}");
|
||||
sb.AppendLine($"{i}else if ({etc} == BinaryTypeCode.Null) {{ {assignNull} }}");
|
||||
sb.AppendLine($"{i}else if ({etc} == BinaryTypeCode.ObjectRef)");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i} }}");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.Null:");
|
||||
sb.AppendLine($"{i} {assignNull}");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i} case BinaryTypeCode.ObjectRef:");
|
||||
if (isArray)
|
||||
sb.AppendLine($"{i} col_{propSuffix}[{indexVar}] = {elemCast}context.GetInternedObject((int)context.ReadVarUInt())!;");
|
||||
else
|
||||
sb.AppendLine($"{i} col_{propSuffix}.{addCall}({elemCast}context.GetInternedObject((int)context.ReadVarUInt())!);");
|
||||
// FixObj slot (0..SlotCount-1): same type via FixObj marker
|
||||
sb.AppendLine($"{i} break;");
|
||||
// FixObj slot (0..SlotCount-1): same type via FixObj marker.
|
||||
// Populate slot cache to keep _nextRuntimeSlot in sync with the serializer.
|
||||
sb.AppendLine($"{i}else if ({etc} < BinaryTypeCode.Object)");
|
||||
sb.AppendLine($"{i}{{");
|
||||
sb.AppendLine($"{i} default:");
|
||||
sb.AppendLine($"{i} if ({etc} < BinaryTypeCode.Object)");
|
||||
sb.AppendLine($"{i} {{");
|
||||
sb.AppendLine($"{i} context.GetWrapper(typeof({elemTypeName}), {etc});");
|
||||
sb.AppendLine($"{i} if ({etc} >= context._nextRuntimeSlot) context._nextRuntimeSlot = {etc} + 1;");
|
||||
sb.AppendLine($"{i} var re_{propSuffix} = new {elemTypeName}();");
|
||||
sb.AppendLine($"{i} {reader}.Instance.ReadProperties(re_{propSuffix}, context, nd_{propSuffix});");
|
||||
sb.AppendLine($"{i} {assignExpr}");
|
||||
sb.AppendLine($"{i} }}");
|
||||
sb.AppendLine($"{i} break;");
|
||||
sb.AppendLine($"{i}}}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue