Skip to content

Unity Support + Mono #36

Description

@DaZombieKiller

First off, awesome project! I am happy to look into contributing parts of this feature if necessary.

Due to the fact that Unity does not use MSBuild or support NuGet, it is currently non-trivial to consume DistIL from it. Some Unity-specific code would need to be written that uses CompilationPipeline.assemblyCompilationFinished to run DistIL. As Unity only supports .NET Standard 2.1 at the latest, it would likely need to use DistIL.Cli rather than running it in-process.

The JIT codegen in legacy Mono (and by extension, Unity) is typically rather poor, but can be significantly improved with the right tricks. I see a lot of potential in this project for improving the situation.

Some potential optimization passes that come to mind are:

  • System.Numerics.Vector4 receives hardware acceleration in Mono (System.Numerics.Plane and System.Numerics.Quaternion do too, if we're talking about dotnet/runtime Mono) so an optimization pass that replaces UnityEngine.Vector4/Unity.Mathematics.float4 with System.Numerics.Vector4 when possible can provide significant improvements.
    • The same actually applies to CoreCLR to an extent -- replacing Godot/XNA's Vector2/Vector3/Vector4/etc. types with the System.Numerics equivalents can significantly improve codegen due to them being intrinsified in the JIT.
    • Vector<T> is not currently accelerated in Unity due to a bug. A fix exists but it has yet to make its way into an update.
  • With the exception of System.Numerics.Vector4 due to its intrinsification, passing numerics types (and their third-party equivalents) by reference may often result in better code under Mono.
  • Some APIs in Unity are unnecessarily implemented in native code and are merely internal calls on the managed side (such as UnityEngine.Quaternion.Inverse, which just negates the x, y and z components. These could be transformed into regular IL implementations to benefit from inlining and avoid the icall overhead.
  • There are many frequently-accessed properties in Unity whose values do not change, yet each access results in an internal call (such as UnityEngine.GameObject.get_transform). An optimization pass could inject a new field into types and cache the result of the internal call to avoid the overhead. This could arguably be considered an invalid optimization due to it changing type layouts.
  • Unity has several APIs that mimic those on System.Runtime.CompilerServices.Unsafe, but due to the fact that they are not intrinsified by Mono they may not always be inlined and can produce worse code. This is not ideal as the Unsafe class is not available in-box due to Unity targeting .NET Standard 2.1 and lacking any NuGet support.
  • Unity has a NativeArray<T> type that is essentially a pointer and length with some allocation and permissions tracking. Many of its members produce less than ideal code under JIT and due to its indexer being by-value rather than by-ref, it can result in a lot of copying. Burst (Unity's toolchain that runs a subset of IL through LLVM) will often optimize these copies out, among other things. An IL optimization pass can bring regular JIT-mode code a bit closer to its performance.
  • In Unity, MemoryExtensions.IndexOf and related APIs that take a StringComparison currently allocate a string copy of the input and forward to the string-based variants. This results in a significant memory and runtime performance issue. It can be somewhat mitigated by checking for StringComparison.Ordinal and forwarding to the other overloads that do not take a StringComparison, but the issue naturally persists for the other comparison types. An IL post processing pass could either embed a Span-based implementation of these comparisons, or call into the private Mono BCL methods that perform them (if I recall correctly, they take pointers at the lowest level).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions