-
Notifications
You must be signed in to change notification settings - Fork 131
What even is AOT
There are some major issues with using Newtonsoft.Json that are related to AOT. It's exactly due these issues this entire project, Newtonsoft.Json-for-Unity, is here to solve. But it cannot do this fully "automagically", we need you to know about these issues too.
The acronym AOT is tossed around a lot in these corners. If you're like me then not knowing how something actually works will bug you to headaches when you use it day-to-day. Here is a brief explanation of AOT and JIT in the context of Unity and Newtonsoft.Json.
Before explaining AOT, we first must clear up two other main concepts: JIT and reflection.
Just-In-Time (JIT) compilation; a relatively old but very hot technology put into many modern runtimes. The word defines compilation that's invoked at the split second before its outcome is to be executed. The JVM and CLR are proud users of this JIT technology, but the definition also includes scripting languages such as JavaScript and Python.
JIT compilation is used to create new code, both native and intermediate, in effort of at runtime optimize performance or simply dynamically generating code.
The act of doing a JIT compilation is sometimes referred to with the verb "jitting".
"In computer science, reflection is the ability of a process to examine, introspect, and modify its own structure and behavior."
From: https://en.wikipedia.org/wiki/Reflection_(computer_programming)
Newtonsoft.Json is not precompiled with every possible JSON schema handling every possible object type. Instead, Newtonsoft.Json contains a lot of clever uses of reflection to figure out the schema of the objects it's working with, but also to create new instances of those types dynamically (i.e. not knowing at compile time which types to instantiate).
This dynamic instantiation sometimes requires jitting.
A common occurrence are generic types. Most times the compiler can through inspecting your code see which generic types are to be used, but sometimes (such as the case with reflection) it cannot. When you then at runtime come across a code path where you need a type the compiled product was not prepared for it boots up the JIT compilation, compiling the code needed to handle that type, then returning back to the code execution as if it always existed.
Example where JIT would be required:
void Example() {
Type listType = Type.GetType("System.Collections.Generic.List`1");
Type listOfStringType = listType.MakeGenericType(new[] { typeof(string) });
// Equivalent to list = new List<string>()
object list = listOfStringType.GetConstructor(new Type[0]).Invoke(new object[0]);
// Equivalent to list.Add("foo")
listOfStringType.GetMethod("Add").Invoke(list, new object[] { "foo" });
// Equivalent to first = list[0]
object first = listOfStringType.GetProperty("Item").GetValue(list, new object[] { 0 });
Console.WriteLine($"First item: {first}"); // outputs: foo
}
It would take a smart compiler to know what generic type to compile from the example above, but even so we could come up with an even be more convoluted variant where the strings being fed through input by the user.
Generation of generic types are fully handled by the CLR upon request.
But there are sometimes we want to generate more than just a generic type,
such as generating full abstract syntax trees of if-statements and function
calls to create a new function out of the blue. That subject is what the oh so
dreaded System.Reflection.Emit
solves. Nothing we will discuss here, except
the fact that Newtonsoft.Json uses it to speed itself up in certain scenarios,
which is why we sometimes come across this error message:
NotSupportedException: /Users/builduser/buildslave/unity/build/External/il2cpp/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/AssemblyBuilder.cpp(20) : Unsupported internal call for IL2CPP:AssemblyBuilder::basic_init - System.Reflection.Emit is not supported.
Ahead-Of-Time (AOT) compilation; let's say it's the default. Hitting the "Build" button and letting your easy to read C# source code be turned into easy to execute .DLL's and .EXE's. AOT compilation is completed at the phase often referred to as "compile-time". Some languages and environments only allow AOT for differing reasons, but that is where we have to know everything in advance.
All the C# code in your program be AOT compiled. Classes, methods,
const values, interfaces, et.al. Generics are compiled to be used as
templates (such as List<>
), and known generic types (such as List<int>
) are
compiled among the rest of the type store. If we want for example a specific
generic type to be compiled with the resulting program, we sometimes need to
help the compiler out by hinting what we actually want.
There is no common verb for the act of "AOT" compilation as there is with "jitting", except for the ambiguous word "compiling".
IL2CPP. What an amazing compiler created by Unity Technologies. It takes intermediate language (IL) code, the input used by the CLR and the output from many different C# compilers such as the Microsoft C# compiler (CSC) or the Mono C# compiler (MCS), and converts it to C++ code, that can later be compiled with tools such as the WebAssembly compiler to effectively run C# in the browser, or iOS compiler to effectively run C# on iPhone!
Nowadays there are many solutions to run C# here and there, but the IL2CPP compiler was one of the first to the market. Groundbreaking!
However, the problem with this is that IL2CPP only supports AOT. The code generated by IL2CPP is not run by the CLR (which handles the generation of generics, remember?) and Unity Technologies have intentionally not implemented System.Reflection.Emit as a design principle.
Why perhaps? It's their shortcut. Run C++ code, which for reference has no JIT capabilities, instead of a full fletched CLR. Compared to the Blazor project, where they run .NET Core code in the browser using WebAssembly by actually loading an entire .NET CLR environment into your browser window, per page. Here with IL2CPP since they AOT compile everything they can be much smarter about what to strip away, such as stripping away the entire classes because they are not used. A royalty that Blazor cannot afford (until they get that promise of full AOT compilation of .NET Core/.NET 5 working).
This means you have to take extra steps when building with IL2CPP to make sure the AOT compilations are as complete as they need to be. If using the scripting backend Mono you have full JIT capabilities at your disposal, however if you're using IL2CPP, you need to take extra precautions. Here's a small table of the supported scripting backends per build target in Unity:
Platform | Scripting backends |
---|---|
Standalone Mac OS X | Mono, IL2CPP (Note: Mac IL2CPP player can only be built on Mac) |
Standalone Windows | Mono, IL2CPP |
Standalone Linux | Mono |
Universal Windows Platform (UWP) | IL2CPP |
tvOS | IL2CPP |
iOS | IL2CPP |
WebGL | IL2CPP |
PS4 | Mono, IL2CPP |
Xbox One | Mono, IL2CPP |
Android | Mono, IL2CPP |
To deal with all of the errors that can occur on this AOT only compiler IL2CPP we have this wiki page to guide you with handling these problems:
Wiki page: Fix AOT compilation errors
new!
Unity's package is now officially ready for public use: Install official UPM package
This package is licensed under The MIT License (MIT)
Copyright © 2019 Kalle Jillheden (jilleJr)
https://github.com/jilleJr/Newtonsoft.Json
See full copyrights in LICENSE.md inside repository
About- Home
-
Install Newtonsoft.Json
Deprecated:
-
Install converters for Unity