Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incompatible with IL2CPP #24

Open
holodia opened this issue Mar 29, 2021 · 3 comments
Open

Incompatible with IL2CPP #24

holodia opened this issue Mar 29, 2021 · 3 comments

Comments

@holodia
Copy link

holodia commented Mar 29, 2021

ExecutionEngineException: Attempting to call method 'InvokableCallback`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.

Callstack:

System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters)
System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes, System.Threading.StackCrawlMark& stackMark)
System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes)
SerializableCallbackBase`1[TReturn].GetPersistentMethod ()
SerializableCallback`1[TReturn].Cache ()
SerializableCallback`1[TReturn].Invoke ()
@rfadeev
Copy link
Contributor

rfadeev commented Sep 21, 2021

Hi,

Could you please provide example code for reproducing the issue? Unity version and target platform would be also helpful.

I tried to reproduce the issue with PC Windows IL2CPP build and I did not get that exception. I used example code from README.md and SerializableCallback<int, MyProduct> callback.

@Esildor
Copy link

Esildor commented Sep 29, 2022

Trying to get some internet points for anyone else that finds this in the future since I also ran into this.

This is how I fixed it, check out the class comments for how and why I think it fixes it. I'm too lazy to rewrite things up here, so just read the class comments 😂

/// <summary>
/// Since comparer nodes and other classes use the SerializableCallback library, which uses
/// reflection to make function calls. These classes/function calls are stripped by
/// the compiler at compile time. This means any function not manually called
/// (in code) gets removed at compile time. Mainly some InvokableCallback<T, J>
/// never get created or used at compile time. In the editor, this works fine
/// since it supports JIT compilation, mobile devices don't. So we manually create and
/// "use" these classes so they are not stripped.
/// 
/// Some thoughts:
/// It's strange since methods that have a single param don't get stripped. But
/// anytime there is a function with 2 or more parameters, it gets stripped and requires
/// this... Not sure why. My only guess would be the SerializableCallback library 
/// serializes 1 param methods differently from X param methods. Notably, Unity 
/// doesn't strip functions that are only used in UnityAction's. I wonder if this lib, or Unity
/// is using some engine feature? 
/// Regardless, defining them manually for each method signature makes it work.
/// </summary>
public static class AOTStubsIL2CPP
{
  public static void Stub()
  {
    // Quests
    new QuestLineIntInvokable(null, string.Empty);
  }

  class QuestLineIntInvokable : InvokableCallback<QuestLine, int, bool>
  {
    public QuestLineIntInvokable(object target, string methodName) : base(target, methodName) { }
  }
}

For my use case above, I needed a method that too 2 params, a QuestLine (custom class in project) and an int. At the bottom, I define the class. Then "use" it in code. From your error message, you can sort of "parse" what the method is.
Attempting to call method 'InvokableCallback`2[[**System.String**, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor'

It looks like you're trying to call a function with the signature of: bool Foo(string bar). So your class might like something like this:

  class FooBarInvokable : InvokableCallback<string, bool>
  {
    public FooBarInvokable (object target, string methodName) : base(target, methodName) { }
  }

Hope this helps lol

@EpsilonD3lta
Copy link

EpsilonD3lta commented Mar 27, 2023

I am no expert on C# compiler but as I understand it, methods are not being "stripped", they are not being created at all. Generic methods are being created by compiler - each type and combination of types it stumbles upon when it reads the code creates a separate method. Since here the methods are constructed in runtime, it does not create those combinations AOT.

As of why some methods with smaller number of parameters do exist - I don't know. In my case, 0 input and 1 output params callbacks were created, callbacks with 1 input and 1 output were not. Maybe compiler does create some basic types? No idea.

But this is the reason why even [UnityEngine.Scripting.Preserve] attribute or linker xml file won't work - the methods aren't stripped - they don't exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants