Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

[SOLVED] Is it possible to "unsafely" call a reflected C# method on iOS?

Discussion in 'Scripting' started by ArConstructor, Oct 22, 2016.

  1. ArConstructor

    ArConstructor

    Joined:
    May 27, 2010
    Posts:
    24
    Hi all,

    I was wondering if it's possible to speed up reflection on iOS (which doesn't allow dynamic code generation) by using "unsafe" method invocation (assuming all arguments are pre-validated to have the right type).

    My idea was to generate a dll with a method containing IL assembler that would trick the application into calling a function by its pointer (MethodInfo.MethodHandle.GetFunctionPointer()). To test if it's possible at all, I generated an assembly using the following code:
    Code (CSharp):
    1. var an = new AssemblyName("RawInvoke");
    2. var ab = System.AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save, Application.dataPath);
    3. var mb = ab.DefineDynamicModule(an.Name, "RawInvoke.dll");
    4. var tb = mb.DefineType("RawInvokeNamespace.RawInvoker", TypeAttributes.Public|TypeAttributes.Class | TypeAttributes.Sealed|TypeAttributes.Abstract);
    5. var fb = tb.DefineMethod("InvokeRaw", MethodAttributes.Public|MethodAttributes.Static, typeof(void), new Type[] { typeof(System.IntPtr) });
    6. var ilg = fb.GetILGenerator();
    7. ilg.Emit(OpCodes.Ldarg_0);
    8. ilg.EmitCalli(OpCodes.Calli, call_conv, typeof(void), System.Type.EmptyTypes);
    9. ilg.Emit(OpCodes.Ret);
    10. var t = tb.CreateType();
    11. ab.Save("RawInvoke.dll");
    Which basically contains 1 static method with an IntPtr agrument and attempts to use "unmanaged code call" on that argument.

    It actually works in Unity editor and on Android, e.g.
    Code (CSharp):
    1. var mi = this.GetType().GetMethod("Method1");
    2. var p1 = mi.MethodHandle.GetFunctionPointer();
    3. RawInvokeNamespace.RawInvoker.InvokeRaw(p1);
    executes without errors (even when Method1 signature isn't exactly void Method1()), with InvokeRaw(p1) being only 1.5~2 times slower than an equivalent delegate call.

    Obviously, I'll need something more advanced to correctly call methods with other signatures. However, this doesn't seem to be the biggest problem: when I tried to build this experiment for the iOS platform, it failed on the "Converting managed assemblies to C++" stage, saying
    So here's my question: does anyone know if it's possible to make IL2CPP compile such a hack? Are there, perhaps, some other options to "unsafely" call a method by its handle/MethodInfo?

    I know it might be more practical for my purpose (a scripting language with intensive access to C#-side stuff) to use something like MoonSharp with "hardwired" access to a predefined set of classes, but I'm still very curious if the "unsafe call" trick can be done in principle :D
     
  2. ArConstructor

    ArConstructor

    Joined:
    May 27, 2010
    Posts:
    24
    Stumbled upon this: http://stackoverflow.com/questions/1184329/function-pointers-in-c-sharp
    Eamon Nerbonne's answer is almost exactly what I wanted and compiles/works for IL2CPP platforms. Not needing unsafe tricks is a big plus ;) The only downside is that I need to generate delegates/wrappers for all possible generic signatures beforehand, but that's not a big issue.