6

I'm trying to figure out what the limitations really means when deploying for iOS from Xamarin.

http://developer.xamarin.com/guides/ios/advanced_topics/limitations/

I was under the impression that you have no JIT and thus any MakeGenericMethod or MakeGenericType would NOT work as that would require JIT compilation.

Also I understood that when running on the simulator, these restrictions does not apply since the simulator is not running in the full AOT (Ahead of Time) mode.

After setting up my Mac so that I could deploy to my phone, I would except the following test to fail when running on the actual device (iPhone).

    [Test]
    public void InvokeGenericMethod()
    {
        var method = typeof(SampleTests).GetMethod ("SomeGenericMethod");

        var closedMethod = method.MakeGenericMethod (GetTypeArgument());

        closedMethod.Invoke (null, new object[]{42});

    }

    public static void SomeGenericMethod<T>(T value)
    {
    }


    private Type GetTypeArgument()
    {
        return typeof(int);
    }

The thing is that completes successfully and I can't really understand why. Does not this code require JIT compilation?

In an effort to "make it break" , I also did a test with MakeGenericType.

    [Test]
    public void InvokeGenericType()
    {
        var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));

        var instance = Activator.CreateInstance (type);

        var method = type.GetMethod ("Execute");

        method.Invoke (instance, new object[]{"Test"});

    }


public class SomeGenericClass<T>
{
    public void Execute(T value)
    {

    }
}

How can this work when there is no JIT?

Am I missing something ?

seesharper
  • 3,249
  • 1
  • 19
  • 23
  • That code can be AOT compiled so it works without issues. Where you will run into limitations is generating IL code. Code generation works on Android and Windows Phone but not on iOS. – SKall Jul 05 '14 at 22:36
  • According to this article, MakeGenericType is going to cause MSIL to be dynamically generated. http://msdn.microsoft.com/en-us/magazine/cc163610.aspx If that is really the case, I don't understand how it could work. – seesharper Jul 05 '14 at 23:09
  • I was actually wrong as the code will fail with aggressive linking option (unless somewhere else in the code there is a reference to SomeGenericClass{string}). See my answer below with some sample code. – SKall Jul 06 '14 at 00:57

1 Answers1

4

In order to make the code fail go to iOS project options, tab "iOS Build" and change the "Linker Behavior:" to "Link all assemblies". Running the code will result in Exception and it will be of type default constructor for type XXX was not found.

Now, make a reference to the SomeGenericClass{string} in your code and the method will run just fine. The two added lines cause the compiler to include SomeGenericClass{string} in the binary. Note that the lines can be anywhere in the application that is compiled into the binary, they don't have to be in the same function.

    public void InvokeGenericType()
    {
        // comment out the two lines below to make the code fail
        var strClass = new SomeGenericClass<string>();
        strClass.Execute("Test");

        var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));

        var instance = Activator.CreateInstance (type);

        var method = type.GetMethod ("Execute");

        method.Invoke (instance, new object[]{"Test"});
    }
SKall
  • 5,234
  • 1
  • 16
  • 25
  • So what you are saying is that as long as the linker behavior is not set to "Link All Assemblies", MakeGenericType and MakeGenericMethod will work? – seesharper Jul 06 '14 at 12:51
  • 1
    Yes because the linker will include all possible combinations of the generic class. This can result in a large binary so a release version usually is recommended to use the aggressive linking. With the default settings I would think it would fail if "SomeGenericClass" was replaced with generic from the SDK libraries. – SKall Jul 06 '14 at 13:07
  • What if I mark class SomeGenericClass<> with a PreserveAttribute? Would it still get linked away? – thomasgalliker Oct 11 '19 at 06:30