Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Are C# Expression Trees (or ILGenerator) allowed on iOS

Discussion in 'Experimental Scripting Previews' started by lluo, Aug 23, 2017.

  1. Nanorock

    Nanorock

    Joined:
    Dec 2, 2012
    Posts:
    41
    Hum too bad ^^'
    Now I can inject / change code within a DLL with Harmony Patcher , which could potentially allow me to expose a method to force AOT to realise use cases, just like this AotHelper for Newtonsoft Json.
    Code (CSharp):
    1.  
    2. public class DeleguateIssue : MonoBehaviour
    3. {
    4.     delegate void Call(int param);
    5.     Call _calledThroughEfficientReflection;
    6.     void OptimizedDelegate(int test) => Debug.Log("Successfully called with "+test);
    7.     void Awake()
    8.     {
    9.         try
    10.         {
    11.             var methodInfo = GetType().GetMethod("OptimizedDelegate", BindingFlags.Instance | BindingFlags.NonPublic);
    12.             var param = Expression.Parameter(typeof(int));
    13.             var callParent = Expression.Call(Expression.Constant(this), methodInfo, param);
    14.             _calledThroughEfficientReflection = Expression.Lambda<Call>(callParent, param).Compile();
    15.             _calledThroughEfficientReflection(5);
    16.         }
    17.         catch (Exception e)
    18.         {
    19.             Debug.LogException(e);
    20.         }
    21.     }
    22. }
    23.  
    It's interesting to see that Expression.Lambda.Compile works,
    However calling the delegate create the following bug at runtime:

    Code (CSharp):
    1. ExecutionEngineException: Attempting to call method 'System.Linq.Expressions.Interpreter.LightLambda::RunVoid1<System.Int32>' for which no ahead of time (AOT) code was generated.
    2.   at UnityEngine.AudioClip+PCMSetPositionCallback.Invoke (System.Int32 position) [0x00000] in <00000000000000000000000000000000>:0
    3.   at DefaultNamespace.DeleguateIssue.Start () [0x00000] in <00000000000000000000000000000000>:0
    4.  
    But I can't find this System.Linq.Expressions.Interpreter.LightLambda or even its namespace in any of the DLL we have. I'm quite confused, but I'm guessing "System.Linq.Expressions.Interpreter" is generated during compilation ?
    If I could understand how/when this is created, maybe I could inject myself somewhere I could help/force AOT compilation.

    Edit: I just realized how wrong/weird is the stack trace ? Why is there UnityEngine.AudioClip+PCMSetPositionCallback.Invoke there o_O
     
    Last edited: Feb 3, 2020
  2. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    This type is an internal class in the System.Core.dll assembly. It is not generated during compilation.

    Yes, that stack trace looks incorrect. Is this part of a project you can submit with a bug report? I'd love to have a look at this in detail to correct the stack trace issue.
     
  3. Nanorock

    Nanorock

    Joined:
    Dec 2, 2012
    Posts:
    41
    Last edited: Feb 4, 2020
  4. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    I'm fairly certain the LightLambda class is in the Mono implementation of the class libraries only. Is this is the System.Core.dll from the Unity installation? If so, what directory is it from?
     
  5. Nanorock

    Nanorock

    Joined:
    Dec 2, 2012
    Posts:
    41
    We finally found it in "Editor\Data\MonoBleedingEdge\lib\mono\unityaot\System.Core.dll". My dotnet peek search must not be working properly ¯\_(ツ)_/¯.
    I'm now studying how I can patch the dll to expose a method that would help the compiler generate AOT code for the types we use.
     
    Mgravitus and JoshPeterson like this.
  6. LVermeulen

    LVermeulen

    Joined:
    Jun 26, 2013
    Posts:
    40
    We're looking into using expression trees to set fields on a large number of components - but it looks like there is a large performance cost with IL2Cpp:
    https://answers.unity.com/storage/temp/159653-il2cppperformance.png (not my image, from https://answers.unity.com/questions/1731418/il2cpp-compiled-expressions-performance.html)

    Is this because it's just using Reflection internally, so there is no advantage to using a expression tree like this rather than a FieldInfo.SetValue()? Doesnt look like there is a way around this
     
    Last edited: Oct 14, 2020
    Thaina likes this.
  7. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    The expression trees implementation used for AOT platforms is an interpreter, so it is pretty slow. A JIT compiler like Mono can do this better by actually compiling the expression trees at run time. If performance is a concern, I would avoid expression trees with IL2CPP.
     
  8. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    Pardon me to digging up this old thread but is this limitation was resolved by any means? Can we use `System.Linq.Expressions` with value type in newer version of unity IL2CPP yet?
     
  9. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    Yes, there is a new option in the Build Settings which will improve the behavior of the Linq expression interpreter. See this forum thread for details: https://forum.unity.com/threads/il2cpp-build-time-improvements-seeking-feedback.1064135/

    You will want to try the "Faster (smaller) builds" option. This is available in in Unity 2021.2 beta releases now.
     
  10. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    Thank you very much
     
  11. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    363
    This is great news! You have my thanks too!
     
  12. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    Worth saying that Apple changed thier TOS some time ago:
     
    Last edited: Aug 3, 2021
    longsl, Thaina, AlejMC and 1 other person like this.
  13. AlejMC

    AlejMC

    Joined:
    Oct 15, 2013
    Posts:
    149
    That's pretty nice.
    Makes me wish that endeavours like MoonSharp or other runtime scripting tools were still maintained.
     
  14. Gustavo-Santos

    Gustavo-Santos

    Joined:
    May 4, 2014
    Posts:
    13
    Could you check if these improvements have already reached the 2021.2 beta? because I've just tried building with "Faster (smaller) builds" option enabled, but I couldn't see any performance improvements on getter/setter compiled expressions. I've built with 2021.2.0b8.3289.
     
  15. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    The latest 2021.2 beta should have everything. The improve behavior was not really about performance improvements at run time, but rather performance improvements at build time.

    The improved behavior was that the expression interpreter should work with the "Faster (smaller) builds" option in a number of cases where it did not work previously. Basically, the "Faster (smaller) builds" option allows generic methods that are not available ahead of time to be constructed at run time. The expression interpreter makes heavy use of functions like this.
     
  16. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    If it's decided that the improved compilation time isn't worth it (maybe say due to decreased runtime performance) could we please still have the interpreter as a fallback in IL2CPP? It would allow stuff which was previously impossible with as far as I am aware no downsides (other than the code size cost of the interpreter). This would be amazing
     
  17. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    Yes, this is coming in 2022.1! We've not completed the work yet, but we plan to have it with that release.
     
    QFSW likes this.
  18. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    Last edited: Aug 25, 2021
  19. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    Only interpreted code works everywhere and is allowed in Apple Developer Program License Agreement 3.3.2 https://developer.apple.com/support...rogram-License-Agreement-20210607-English.pdf
     
    Last edited: Aug 25, 2021
  20. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    It doesn't required to be downloaded or installed. At the very least is allow dynamic type which is not change primary purpose of everything. It also enabled a feature in game that allow user to write a code to control the game, or direct modding of the program without losing performance (this is not downloaded or installed and if it was the intended purpose of the game it should also allowed too, it even declare permission in the next paragraph)

    The `interpreted code` mention there I think it not meant to limit only interprete mechanism. I think it include JIT and any scripting system. And we could just avoid making store or storefront
     
  21. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    Splendid! So is this something that will need to be enabled by the user in some way or will all IL2CPP builds on 2022.1+ support dynamically created value type generics? (due to the new interpreter)
     
  22. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    At the moment we don't have plans to enable full JIT support and Sytstem.Reflection.Emit on iOS. We also don't have a generalized IL interpreter, so I think that Unity will remain AOT for iOS.
     
    Thaina likes this.
  23. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    That is still yet to be determined. The technology to fall back to fully shared generics has been merged into IL2CPP. We're working now on how to expose it to the user. I suspect that it will always be present by default, with an option to disable it. But that outcome is not certain yet.
     
    quabug likes this.
  24. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    Thank you for your response. Are there any consideration about mono on ios? Or dotnet 6 on ios and android?
     
  25. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    We don't have any plans to support Mono AOT or JIT on iOS now.

    For .NET 6, we're still looking at the best options for runtimes across all platforms, so I can't say what Unity will support at this time.
     
    Thaina likes this.
  26. Gustavo-Santos

    Gustavo-Santos

    Joined:
    May 4, 2014
    Posts:
    13
    @JoshPeterson Imagine I'm building to Android (IL2CPP), it is possible somehow to have those expressions compiled on a PostBuild processor? Something like Mono.Cecil, but with expressions instead? If yes, do you have any sample or guidance? Thanks in advance
     
  27. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    No, we don't have any way to do that, unfortunately.
     
  28. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    That's unfortunate. Looking at trends more and more games allow players to be creators (roblox best example). There are many Unity games that refuse to add scripting as it's not cross platform (won't work in il2cpp ios). Hopefully that will change at some point. This should have a bit higher priority. As you can imagine players that end up learning and scripting in C# in a game would have pretty easy way of picking up Unity. In a sense it's a way of converting players to Unity users.

    Worth saying that Unreal noticed it and they're adding new language for that exact purpose https://twitter.com/Nephasto/status/1340046706642186247/


    Another take on this feature is new Battlefield Portal with visual scripting:


    Maybe that's something that could be done as there's even "High performance interpreter" on visual scripting roadmap https://unity.com/roadmap/unity-platform/gameplay-ui-design
     
    Thaina likes this.
  29. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    Thanks for the feedback. I not quite sure the "High performance interpreter" for visual scripting is - it might be an interpreter for the script graph. I'll raise this internally though as a request with our Product Management group.
     
    Thaina and Kamyker like this.
  30. skyake

    skyake

    Joined:
    Jun 7, 2019
    Posts:
    11
    .NET has an interpreter fallback to make ExpressionTree work in NativeAOT scenario: https://github.com/dotnet/runtime/t...sions/src/System/Linq/Expressions/Interpreter
    And they use predefined constants (FEATURE_COMPILE and FEATURE_INTERPRET) to determine whether to enable it or not: https://github.com/dotnet/runtime/b...tem/Linq/Expressions/LambdaExpression.cs#L147

    You may want to see how they defined those constants for building NativeAOT runtime: https://github.com/dotnet/runtimelab/tree/feature/NativeAOT
     
    Thaina likes this.
  31. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    Are there any progress about this feature?
     
  32. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    Celezt, LaireonGames, Arkade and 2 others like this.
  33. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,168
    Thank you so much for your all hard work
     
  34. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    Don't thank me! I'm just the messenger here. The .NET VM Team at Unity is pretty awesome - they have implemented this.
     
  35. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    @JoshPeterson If they don't select this option, can we still exist the full generic sharing to be present and hence fix these reflection like issues we're having? Does that option enable generic sharing or does it force generic sharing over dedicated compilation? Thanks!
     
  36. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    655
  37. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    There is a distinction in the behavior in Unity version 2021.2 and version 2022.1.

    In Unity 2021.2, you must change the IL2CPP Code Generation option, and then you will _only_ get the fully shared generics for value types. While this will eliminate execution engine exceptions and reflection issues around value type generics, it does mean that the only version of value type generics used is one with slower run time performance vs the versions where IL2CPP can determine what the generic type arguments are.

    In Unity 2022.1, IL2CPP _always_ generates a fallback to the fully shared versions, but prefers to call the unshared versions where it can. This allows for improved run time performance when IL2CPP can determine the generic type arguments at compile time, while still ensuring proper JIT-like behavior in cases where it cannot.

    In Unity 2022.1 and later, only change the IL2CPP Code Generation option if you are looking for faster build times or smaller code size in your project.

    In Unity 2021.2 the complete feature was not ready (the fallback option) - but we wanted to ship the part that was ready, as it can help some use cases. I consider 2022.1 and later the versions that are feature complete - with these versions you can get both good performance and better behavior. And you have the option to optimize for either runtime performance or code size.
     
    Thaina likes this.
  38. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    They should work without any constraints on behavior. However, I would not plan to use expression trees in any performance sensitive code, and IL2CPP cannot optimize it as all was a JIT engine can.
     
    Thaina likes this.
  39. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    How it works in 2022.1 sounds perfect, and I understand why it didn't work like that in 2021 (wanted to get it out earlier in some form until it was ready)
    Thanks for staying on top of this over all these years! Very exciting
     
    JoshPeterson likes this.