C
C#2mo ago
Nolram

NativeAOT Serialization Troubles

I'm trying to serialize the following (in an ideally fast manner and binary format, but I am willing to compromise) using NativeAOT (this is a requirement!): A class containing a custom SparseSet (2 arrays internally) implementation containing a set of classes deriving from a shared interface. I'm currently using MemoryPack for this, however it is not working whatsoever, and the following error occurs:
Process terminated. Failed to create generic virtual method implementation

Declaring type: MemoryPack.Formatters.MemoryPackableFormatter`1<GameCore.Scenes.Scene>
Method name: Serialize
Instantiation:
Argument 00000000: MemoryPack.Internal.ReusableLinkedArrayBufferWriter

at System.RuntimeExceptionHelpers.FailFast(String, Exception, String, RhFailFastReason, IntPtr, IntPtr) + 0x249
at Internal.Runtime.TypeLoader.TypeLoaderEnvironment.ResolveGenericVirtualMethodTarget(RuntimeTypeHandle, RuntimeMethodHandle) + 0x256
at System.Runtime.TypeLoaderExports.<>c.<GVMLookupForSlotSlow>b__8_0(IntPtr, IntPtr, Object, IntPtr&) + 0x3e
at System.Runtime.TypeLoaderExports.CacheMiss(IntPtr, IntPtr, RuntimeObjectFactory, Object) + 0x3c
at System.Runtime.TypeLoaderExports.GVMLookupForSlotSlow(Object, RuntimeMethodHandle) + 0x68
at System.Runtime.TypeLoaderExports.GVMLookupForSlot(Object, RuntimeMethodHandle) + 0x91
at MemoryPack.MemoryPackWriter`1.WriteValue[T](T&) + 0x3d
at MemoryPack.MemoryPackSerializer.Serialize[T](T&, MemoryPackSerializerOptions) + 0x342
at Game.Main(String[] args) + 0xaa
Process terminated. Failed to create generic virtual method implementation

Declaring type: MemoryPack.Formatters.MemoryPackableFormatter`1<GameCore.Scenes.Scene>
Method name: Serialize
Instantiation:
Argument 00000000: MemoryPack.Internal.ReusableLinkedArrayBufferWriter

at System.RuntimeExceptionHelpers.FailFast(String, Exception, String, RhFailFastReason, IntPtr, IntPtr) + 0x249
at Internal.Runtime.TypeLoader.TypeLoaderEnvironment.ResolveGenericVirtualMethodTarget(RuntimeTypeHandle, RuntimeMethodHandle) + 0x256
at System.Runtime.TypeLoaderExports.<>c.<GVMLookupForSlotSlow>b__8_0(IntPtr, IntPtr, Object, IntPtr&) + 0x3e
at System.Runtime.TypeLoaderExports.CacheMiss(IntPtr, IntPtr, RuntimeObjectFactory, Object) + 0x3c
at System.Runtime.TypeLoaderExports.GVMLookupForSlotSlow(Object, RuntimeMethodHandle) + 0x68
at System.Runtime.TypeLoaderExports.GVMLookupForSlot(Object, RuntimeMethodHandle) + 0x91
at MemoryPack.MemoryPackWriter`1.WriteValue[T](T&) + 0x3d
at MemoryPack.MemoryPackSerializer.Serialize[T](T&, MemoryPackSerializerOptions) + 0x342
at Game.Main(String[] args) + 0xaa
I've attached a sample of this scenario reproducing the above error. It works fine when not using NativeAOT, but as I mentioned NAOT is a requirement for me. If anyone has any ideas on how to get this to serialize at all - no matter using what library or whatever - please inform me!
9 Replies
Angius
Angius2mo ago
Should be fixed in 8.0 tho
Nolram
NolramOP2mo ago
This issue is happening on .NET 9, so clearly something still seems wrong I have read this and followed their documentation, but as I just mentioned, the issue still occurs. Other MemoryPack serialisations work; just not this stack of generic container & interface-derived class
Decrypted
Decrypted2mo ago
Iirc we had some issues where ModuleInitializer was not called with NativeAOT for some reason and union types were not registered. Had to manually register them. Like
// (ushort, Type)[]
var formatter = new DynamicUnionFormatter<IFooBarBaz>(
(0, typeof(Foo)),
(1, typeof(Bar)),
(2, typeof(Baz))
);

MemoryPackFormatterProvider.Register(formatter);
// (ushort, Type)[]
var formatter = new DynamicUnionFormatter<IFooBarBaz>(
(0, typeof(Foo)),
(1, typeof(Bar)),
(2, typeof(Baz))
);

MemoryPackFormatterProvider.Register(formatter);
Could also have been that none of the ModuleInitializers were called and as a result all types had to be registered manually. Don't have access to the project anymore and cannot check sorry
Nolram
NolramOP2mo ago
Thank you for your input - I have already tried this, and unfortunately this does not solve the issue. The issue does not seem to be that NAOT is stripping out serialisation logic, but rather that something in the NAOT runtime itself seems to fail.
Clément
Clément2mo ago
Did you already try to configure the trimmer with a root descriptor file to tell it not to trim away specific assemblies/types/... ?
Nolram
NolramOP2mo ago
I believe I have - but I can try again, just in case. (Git issue about this: https://github.com/dotnet/runtime/issues/113664)
Nolram
NolramOP2mo ago
Seems a PR regarding this issue has been created! https://github.com/dotnet/runtime/pull/113684
GitHub
Fix dynamic static generic virtual method dispatch on generic types...
Fixes #113664. When we resolve dispatch for a static generic virtual method dynamically (e.g. after MakeGenericType or another generic virtual method call) we run the runtime type loader logic to d...
Nolram
NolramOP2mo ago
... and merged!

Did you find this page helpful?