AOT compilation problem - ExecutionEngineException - AOT not compiling as expected.

Hello people. Have a problem with with compilation to an AOT platform. Have found a number of posts on the subject, but still haven’t been able to solve my problem. Any help will be very much appreciated!

I’m trying to port an existing project to a platform where JIT compilation is not possible. The project is networked and makes use of generic types, and when running the project I get the following error message:

ExecutionEngineException: Attempting to JIT compile method 'dk.Apex.NightSkies.Networking.PhotonFS.PhotonNetworkConnection:HandleNetworkMessage<object, int> (string,object,int)' while running with --aot-only.

I read the Unity documentation (Unity - Manual: Scripting restrictions) and attempted to implement a similar solution for my problem. When that did not work, I made a project containing the sample problem from the documentation, and it worked as described in the documentation.

I made a sample project with the bare bones of the code that’s giving me problems, and I managed to reproduce the issue. I’ll include the code, in case someone wants to attempt to replicate the issue.

We have an abstract network connection class:

using UnityEngine;

namespace dk.Apex.NightSkies.Networking
{
    public abstract class ANetworkConnection : MonoBehaviour
    {
        protected static ANetworkConnection instance;
        public static ANetworkConnection Instance
        {
            get { return instance; }
        }

        protected void Awake()
        {
            //Debug.Log("nc awake");
            instance = this;
        }

        //handle network messages/events, pass them to server response handler
        public abstract void HandleNetworkMessage<T, H>(string cmd, T content, H user);
    }
}

And a photon specific version (the abstract networking class is there to facilitate switching network solutions). This includes the method that should force the compiler to AOT compile a version of the HandleNetworkMessage method:

using UnityEngine;
using System;

namespace dk.Apex.NightSkies.Networking.PhotonFS
{
    public class PhotonNetworkConnection : ANetworkConnection
    {
        public override void HandleNetworkMessage<T, H>(string cmd, T content, H user)
        {
            Debug.Log("MEH I'MA DOING STUFF!");
        }

        public void UsedOnlyForAOTCodeGeneration()
        {
            HandleNetworkMessage<object, int>("meh", new object(), 42);
            HandleNetworkMessage((string)"meh", (object)new BasicInfo(), (int)1);

            // Include an exception so we can be sure to know if this method is ever called.
            throw new InvalidOperationException("This method is used for AOT code generation only. Do not call it at runtime.");
        }
    }
}

Also a bare-bones network data type + abstract network data type:

namespace dk.Apex.NightSkies.Networking
{
    public class BasicInfo : ANetworkDataType
    {
        public static object Deserialize(byte[] bytes)
        {
            BasicInfo obj = new BasicInfo();
            //obj = (BasicInfo)Unpack(bytes, obj);
            return obj;
        }
    }
}

and

namespace dk.Apex.NightSkies.Networking
{      
    //abstract class for all network data types
    public abstract class ANetworkDataType
    {
    }
}

And finally the script that tests that calls the method:

using UnityEngine;
using dk.Apex.NightSkies.Networking;

public class JITTest : MonoBehaviour {
	void Start ()
    {
        ANetworkConnection.Instance.HandleNetworkMessage("string", new BasicInfo(), 2001);
	}
}

I would expect the inclusion of the UsedOnlyForAOTCodeGeneration method would force the compiler to prepare an version of that method, but it does not work as I expect. Am I overlooking or misunderstanding something?

One suggestion that I often read is using IL2CPP in stead of MONO as the scripting backend. That solution makes my code throw a LOT of null reference exceptions. As it would produce a lot of extra work in all corners and it would definitely be much nicer to just get it working with the mono backend.

Hope someone has some suggestions!

Hi @NerdClown ,
when using mono AOT and overriding generic virtual methods, you are going to get into trouble, because there is no compiled version of the generic type of the derived class. There are only a compiled version of the generic type on the base class.

What you could do is to have HandleNetworkMessage<T, H> in an Interface, put it on the derived class and implement that instead, that would work because AOT would compile the generic types directly. You could also basically make HandleNetworkMessage<T, H> virtual with a bogus body in the base class, and in the derived class mark it as new. Not that, that would be a nice solution.