Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question [IL2CPP] Why is Linq.Contains being code stripped?

Discussion in 'Scripting' started by drallcom3, Apr 16, 2021.

  1. drallcom3

    drallcom3

    Joined:
    Feb 12, 2017
    Posts:
    163
    My code (and it's the only code in the project):
    Code (CSharp):
    1. public enum SomeEnum
    2.     {
    3.         None = 0,
    4.         One = 1,
    5.         Two = 2,
    6.         Three = 3
    7.     }
    8.  
    9.     [Preserve]
    10.     private void Awake()
    11.     {
    12.         int[] array = { 0, 1, 2, 3 };
    13.         Debug.Log(array.Contains(1));
    14.  
    15.         int[] array2 = (int[])Enum.GetValues(typeof(SomeEnum));
    16.         Debug.Log(array2.Contains(1));
    17. }
    The log:
    Code (Boo):
    1. 2021/04/16 23:40:35.665 21740 21763 Info Unity True
    2. 2021/04/16 23:40:35.788 21740 21763 Error Unity MethodAccessException: Attempt to access method 'System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator' on type 'ApkTest.SomeEnum[]' failed.
    3. 2021/04/16 23:40:35.788 21740 21763 Error Unity   at System.Linq.Enumerable.Contains[TSource] (System.Collections.Generic.IEnumerable`1[T] source, TSource value, System.Collections.Generic.IEqualityComparer`1[T] comparer) [0x00000] in <00000000000000000000000000000000>:0
    4. 2021/04/16 23:40:35.788 21740 21763 Error Unity   at ApkTest.Awake () [0x00000] in <00000000000000000000000000000000>:0
    5. 2021/04/16 23:40:35.788 21740 21763 Error Unity
    6.  
    Note: array2 is valid and with a simple foreach loop I can determine that it contains the value. Only the Contains() part is broken.

    I even made a link.xml (same result if it exists or not or if I include everything):
    Code (Boo):
    1. <linker>
    2.     <assembly fullname="System">
    3.         <!-- No issue on these, though they are quite commonly used. -->
    4.         <type fullname="System.ComponentModel.*Converter" preserve="all"/>
    5.         <type fullname="System.Collections.*" preserve="all"/>
    6.         <type fullname="System.Linq.*" preserve="all"/>
    7.         <type fullname="System.Linq.Enumerable.*Contains" preserve="all"/>
    8.     </assembly>
    9. </linker>


    When I make a build (Android APK) with Mono, everything works fine.
    When I make a build with IL2CPP (on low), the error happens.
    This suggests something gets stripped away, but I can't seem to prevent it. Nothing works.
    Does someone have an idea?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    The stripping is probably happening at the IL2CPP compile level. Look in the source to see if that method made it through (it will be hard as the method names are all garbled, but it should be visible), then you know it's being stripped at the compile level.

    If the methods don't make it to IL2CPP then your link thingy above isn't working.

    I don't know how the <T> stuff gets expanded and/or known for stripping, so there ends my knowledge... :)
     
    Joe-Censored likes this.
  3. vitaliano_fanatee

    vitaliano_fanatee

    Joined:
    Oct 9, 2020
    Posts:
    37
    I'm not sure why the stripping is happening, but from what I've understood from the log, I suppose that trying a different approach to cast the Enum array into an int array, may solve the problem.
    Maybe you can try something like this:
    Code (CSharp):
    1.  var array = Array.ConvertAll(Enum.GetValues(typeof(SomeEnum)), item => (int)item);
    Or using the Cast method from Linq:
    Code (CSharp):
    1. Enum.GetValues(typeof(SomeEnum)).Cast<int>().Contains(1)
     
    Last edited: Apr 21, 2021
  4. drallcom3

    drallcom3

    Joined:
    Feb 12, 2017
    Posts:
    163
    Where do I find that source?

    I have a workaround (I use a dumb loop, since it's not used often). I'm just wondering, why the stripping happens.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Unity writes it to disk somewhere at build time. I'm only familiar with iOS, which writes it to an XCode project which you then build. I've never bothered to find it anywhere else but we know it exists since something else always does the actual compilation of the IL2CPP code, AFAIK.
     
  6. vitaliano_fanatee

    vitaliano_fanatee

    Joined:
    Oct 9, 2020
    Posts:
    37
    My guess is that according to this log
    Error Unity MethodAccessException: Attempt to access method 'System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator' on type 'ApkTest.SomeEnum[]' failed.
    , even after the cast, the type of your array is 'ApkTest.SomeEnum[]' and as you don't have any explicit call that reference the GetEnumerator method from the ApkTest.SomeEnum[] type, the method is stripped.
     
  7. drallcom3

    drallcom3

    Joined:
    Feb 12, 2017
    Posts:
    163
    I did try it with all sorts of explicits calls and the result was the same.
     
  8. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,992
    I'm with vitaliano_fanatee here, Enum.GetValues is a freakshow and is likely the problem. It creates a list of "enum". Even assigning it int[] A=(int[])(...) still has it as an array of enums which prints itself as ints.