- Home /
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 (https://docs.unity3d.com/Manual/ScriptingRestrictions.html) 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!
Answer by HaraldNielsen · Mar 12, 2017 at 06:42 PM
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.
Hi @eble
Thanks for the response! Good info in there. Both suggested solutions work, and neither seem to require the stuff in the UsedOnlyForAOTCodeGeneration method. In the end I landed on a third solution that's only slightly different.
I wish I knew a bit more about the workings of the compiler/runtime: I still don't really understand why the calls to HandleNetworkConnection from the UsedOnlyForAOTCodeGeneration method (which afaik should be a reference to the method in the PhotonNetworkConnection, not in the abstract class) does not force the compiler to generate an object/int version of the method for the PhotonNetworkConnection.
Oh well, problem solved, thanks a bunch.
@NerdClown Np.
You could say that its an error in $$anonymous$$ono AOT. Im sitting with the same problem as you currently and therefor looked a bit into it. If you look in IL code, it tells the instance to call the method, that is the type of the base class: IL_0001: newobj instance void DerivedClass::.ctor()
...
IL_0009: callvirt instance !!0/*bool*/ BaseClass::ApplyTo<bool>(!!0/*bool*/)
So when AOT goes trough this, its looking for the compiled generic type (in this case bool) on both the the base and derived class. And for some reason, it has only compiled the BaseClass::ApplyTo<bool>
type. I think It just looks on the IL and chooses to build the BaseClass::ApplyTo<bool>
part
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Unity compilation order 2 Answers
Multiple Cars not working 1 Answer
An OS design issue: File types associated with their appropriate programs 1 Answer