Unity hat am 2. Juli 2015 die Arbeitsweise von P/Invoke-Wrappern in IL2CPP beschrieben. Die technische Serie zeigt, wie das Scripting-Backend Aufrufe aus verwaltetem C#-Code in native C++-Funktionen überführt. Für Spieleentwickler ist diese Verbindung wichtig, wenn ein Projekt auf Plattform-APIs oder eigene native Plugins zugreift.
P/Invoke bezeichnet eine Schnittstelle zwischen verwaltetem Code und Funktionen, die außerhalb der Laufzeit bereitstehen. IL2CPP erzeugt aus den externen Methoden eines Unity-Projekts C++-Wrapper. Diese Wrapper bereiten Parameter für den Aufruf vor und übernehmen nach der Rückgabe die Übergabe an die C#-Seite.
Der Beitrag knüpft an die zuvor erklärte IL2CPP-Struktur an. Das Backend besteht aus einem Ahead-of-Time-Compiler und einer Laufzeitbibliothek. Der Compiler erzeugt den nativen Code, während die Laufzeit unter anderem Speicherverwaltung, Threads und die Kommunikation mit externen Funktionen bereitstellt.
Generierte Wrapper übernehmen die Typumwandlung
Bei einfachen, sogenannten blittable Datentypen kann IL2CPP die Speicherrepräsentation zwischen C# und C++ weitgehend direkt verwenden. Bei nicht blittable Typen ist eine Konvertierung nötig. Dazu zählen unter anderem Zeichenketten, Arrays und komplexere Strukturen. Die erzeugten Wrapper legen dafür temporäre Daten an und geben sie nach dem nativen Aufruf wieder frei.
Wie hoch der Aufwand ausfällt, hängt deshalb nicht nur von der aufgerufenen Funktion ab. Auch die Parameter und ihre Speicherrepräsentation bestimmen, wie viel Marshalling-Code ausgeführt wird. Unity weist darauf hin, dass nicht blittable Typen bei häufigen Aufrufen spürbare Kosten verursachen können. Die generierten C++-Dateien machen diese Abläufe für die Analyse eines Projekts sichtbar.
P/Invoke bleibt mit Mono kompatibel
IL2CPP unterstützt laut Unity dieselben Marshalling-Verhaltensweisen wie das Mono-Backend. Damit können bestehende P/Invoke-Schnittstellen grundsätzlich auf beiden Backends eingesetzt werden. Für die Optimierung lohnt sich dennoch ein Blick auf den generierten Code, besonders wenn native Aufrufe in engen Schleifen oder während eines Frames mehrfach stattfinden.
Der Beitrag war Teil einer technischen IL2CPP-Reihe. Nach den P/Invoke-Wrappern behandelte Unity weitere Aspekte der Speicherbereinigung und der generierten Laufzeit. Die einzelnen Artikel richteten sich an Entwickler, die Plattformcode und native Bibliotheken in Unity-Projekten einsetzen.
