Telegram Web
Channel created
Managed to implement calls with IL calli opcodes, both to managed and unmanaged function pointers.
This tricks could be used to manual function devirtualizing and calling managed functions without reflection and GC/boxing allocations.

FuncUnity wrapper is perfect to use within Unity because IL2CPP RuntimeMethodHandle.Value is an ACTUAL function pointer, and in Mono land this structure contains GetFunctionPointer(). This wrapper expects IL2CPP function pointer to be marked with (funcPtr | 0x80000000000000), that's beyond application address space, so we are safe here.

Of course it's possible to use FuncManaged with IL2CPP, but it could be not peak perf tho.
Working on cross-runtime unsafe library for C# and Unity.
Right now we are having:
ArrayAccess: unsafe access to managed arrays (type replacement, getting data pointers etc). It's also possible to create non-GC array with the custom allocator.

ListAccess: array replacement, thread-safe Add, non-erasure count changing)

StringAccess: mutating the string, copying from ASCII or any other encoding, changing length, etc.

ObjectAccess: basically MonoObject or CLR object header. It's possible to change VTable right now.
Finally managed to create a generic solution for direct function calling. This will even work under Burst, because it allows to use calli unmanaged cdecl calls, and .NET runtime can provide us this with Marshal.GetFunctionPointerForDelegate.

Tho this call creates some wrapper and reverse P/Invoke call, on IL2CPP it's absolutely useless, so we can call this function directly.

FuncIL2CPP/FuncIL2CPPStatic provides us this ability and we can safely use it within burst and call managed land functions without any conversion.

GetUnityCaller() returns a special call which can directly call IL2CPP methods without jumping to RuntimeMethodHandle->methodPtr again in again. This caller works in cross-runtime mode, so you can use it without unity without any limitations, tho it will give very little performance penalty.

For some reason IL2CPP doesn't compile the code where TReturn is returned by ref with Fully Shared Generics enabled, this is why I'm using RefReturn struct to overcome this behavior.

P.S. Different platforms using different function pointer alignment, WebGL doesn't restricts function to be aligned by 1 byte, which means I can't use first bit to store isIL2CPP flag, while Android ARMv7 (32bit) allows functions to store last bit, so I can't use it either. So for Unity IL2CPP direct calls I've made 64-bit field for funcPtr (even on 32-bit platforms) and use last (0x8000000000000000) bit as indicator for IL2CPP direct call. To make direct il2cpp calls faster it's possible to reinterpret to AsIL2CPP() if you are sure that you are running on IL2CPP.

#if ENABLE_IL2CPP
FuncIL2CPP func = unityCall.AsIL2CPP();
#else
FuncManaged func = unityCall.AsManaged();
#endif
👏3🔥2
Unity have implemented fully generic shared function generation, when generic params could be both reference types or struct types to generate less code, but when calli opcode is encountered with an unmanaged call it will generate exception. Though it's ok because we don't need fully generic sharing, we always know argument types upfront. This exception throw will fully replace the call.
And by "fully" I mean FULLY. Yes, with returning value too. Then it referencing intptr_t L_11 which should be a return value, and since it's now non-existent, well, the variable became non-existent too leading to compile errors. This is only the case when TReturn is a reference type, of there's no TReturn at all (returning a void* for instance)
https://github.com/Meetem/ILCall

ILCall is now released at version 1.0.0 🎉🎉
You can make your IL additions by using provided sln to generate new ILCall.dll.

Binaries could be found in "Releases" section on GitHub.
👍6
An article on getting field offset of struct or class object, and how to make it cross-runtime, so it works in Unity (Mono/IL2CPP) and real dotnets.

Field offsets are good stuff to read/write fields without incurring into reflection, so we can avoid TypedReferences (not supported in IL2CPP) and also we avoid GC allocations for fieldInfo.SetValue(object target, object value), if both target and value are structs that's two boxing operations!

Let's dive in!
https://meetemq.com/2023/09/10/nets-fields-and-their-offsets/
🔥5
Запустил стрим, подпиливаем и пересобираем dotnet-runtime, буду юзать его для кастомного движка в поддержкой шарпа

https://www.youtube.com/live/U57DD1g6_nA?feature=shared
9👍1
2025/10/23 03:00:09
Back to Top
HTML Embed Code: