Skip to content
This repository has been archived by the owner on Oct 6, 2023. It is now read-only.

Fix AOT using AotHelper

kalle (jag) edited this page Aug 27, 2021 · 4 revisions

The problem

Let's say you get this error:

ExecutionEngineException: Attempting to call method 'Newtonsoft.Json.Utilities.CollectionWrapper`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.

-or, in other (less verbose) words:

Attempting to call constructor of type Newtonsoft.Json.Utilities.CollectionWrapper<int> for which no ahead of time (AOT) code was generated.

What's going on here is that you're using a type that the compiler did not see needed for compiling into the built product.

You most often will come across this error when deserializing some class containing some field/property of an IList<>, ICollection<>, IDictionary<> or some other generic, and most usually in AOT targets such as when building with IL2CPP towards Windows, Android, iOS, or WebGL.

Common collection types that appear with this error:

System.Collections.Generic.List<T>
System.Collections.Generic.HashSet<T>
System.Collections.Generic.Dictionary<TKey, TValue>
Newtonsoft.Json.Utilities.CollectionWrapper<T>
Newtonsoft.Json.Utilities.DictionaryWrapper<TKey, TValue>
Newtonsoft.Json.Serialization.DefaultContractResolver.EnumerableDictionaryWrapper<TKey, TValue>

Similar error might also occur for other types that the below solution still provides solution for.

The fix

There is a utility class inside Newtonsoft.Json-for-Unity at Newtonsoft.Json.Utilities.AotHelper that allows forcing the compiler to generate code for a type. To use it you may create a MonoBehaviour script to enforce some types you know you will be using.

Sample usage:

using Newtonsoft.Json.Utilities;
using UnityEngine;
 
public class AotTypeEnforcer : MonoBehaviour
{
    public void Awake()
    {
        AotHelper.EnsureList<int>();
    }
}

This script does not need to be added to a GameObject. It just needs to be compiled. Inheriting from UnityEngine.MonoBehaviour or UnityEngine.ScriptableObject will ensure to always be compiled.

To get full information about how you can use AotHelper and it's methods visit the wiki page linked in the header above.

Compared to the other solutions

-as by "other solutions", we're referring to the solutions proposed in the "The alternatives" section of the Fix Aot compilation errors wiki page.

The AotHelper class ensures compilation of a type AND ensures a type is not stripped, instead of just ensuring a type is not stripped. This is especially important when it comes to generic types.

Whereas using link.xml you can tell IL2CPP not to strip away MyClass<double>, but that does not matter if it has not been compiled to begin with. Using AotHelper then we tell the C# to IL compiler (usually csc or msc) to ensure that MyClass of the generic type double is in fact also AOT compiled, at the same time it's implicitly letting IL2CPP know to not strip it away.

Marvels!

As for comparing to usage of the Preserve attribute, it falls short as the Preserve attribute cannot target specific generic types at all.

Clone this wiki locally