views:

264

answers:

1

I'm developing for the iPhone using C# and Mono's Full AOT technology. According to their Limitations page (link text), unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being compiled on demand by a JIT compiler.

When running on the hardware, the following exception occurs:

ExecutionEngineException: Attempting to JIT compile method 'System.Reflection.MonoProperty:GetterAdapterFrame<Image, UnityEngine.Color> (System.Reflection.MonoProperty/Getter`2<Image, UnityEngine.Color>,object)' while running with --aot-only. 

System.Reflection.MonoProperty.GetValue (System.Object obj, System.Object[] index) [0x00000] 
Ani+AniValue.Get () 
Ani.CreateAnimations (System.Object obj, System.Collections.Hashtable properties, Single duration, System.Collections.Hashtable options, AniType type) 
Ani.Method (AniType type, System.Object obj, Single duration, System.Collections.Hashtable _properties, System.Collections.Hashtable _options) 
Ani.From (System.Object obj, Single duration, System.Collections.Hashtable _properties) 
xObject+<>c__CompilerGenerated5.MoveNext () 
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) 
xObject:StartAnimation(Animate, GameObject, Object, Object) 
SceneSplash:CreateBackground() 
SceneSplash:OnSetup() 
SceneSplash:OnSceneActivate(Callback) 
GameController:ActivateScene() 
GameController:DeactivateScene() 
GameController:SceneLoaded(Scene, GameObject, SceneBase) 
SceneBase:Start()

According to the Limitations document, System.Reflection.Emit is not supported, but they state that as side from Reflection.Emit, "the entire Reflection API, including Type.GetType("someClass"), listing methods, listing properties, fetching attributes and values works just fine."

I've included the code that is causing the exception ...

void CreateAnimations(System.Object obj, Hashtable properties, float duration,
                      Hashtable options, AniType type)
{
    foreach (DictionaryEntry item in properties)
    {
        name = (string)item.Key;                  // Extract name and value
        System.Object value = item.Value;

        AniValue foo = new AniValue(obj, name);   // Create value object

        /* To exception occurs inside Get() */
        System.Object current = foo.Get();        // Get current value

        ...

The above method grabs a property name from a hashtable, and uses it (along with obj) to create an instance of AniValue. Just afterward, foo.Get() is called to retrieve the value of the property. The exception occurs on propertyInfo.GetValue(obj, null).

using System.Reflection

public class AniValue
{
    static BindingFlags bFlags = BindingFlags.Public | BindingFlags.NonPublic
                                 | BindingFlags.Instance | BindingFlags.Static;

    System.Object obj;  // Object a field or property is animated on
    string name;        // Name of the field or property

    System.Type objType;          // Type object
    FieldInfo fieldInfo;          // FieldInfo object
    PropertyInfo propertyInfo;    // PropertyInfo object

    public AniValue(System.Object o, string n)
    {
        obj = o;
        name = n;
        objType = obj.GetType();
        fieldInfo = objType.GetField(n, AniValue.bFlags);
        propertyInfo = objType.GetProperty(n, AniValue.bFlags);
        if (fieldInfo == null && propertyInfo == null)
        {
            throw new System.MissingMethodException("Property or field '" + n
                                                    + "' not found on " + obj);
        }
    }

    // Get field or property
    public System.Object Get()
    {
        if (propertyInfo != null)
        {
            /* The next line causes the Exception */
            return propertyInfo.GetValue(obj, null);
        }
        else
        {
            return fieldInfo.GetValue(obj);
        }
    }
    ...

Although I have limited experience with C#, JIT, AOT, and Reflection, should GetValue() trigger JIT? UnityEngine.Color is a struct, and the Image class is as subclass of xObject, which is a subclass of UnityEngine.MonoBehaviour. Color is a property of Image, and that is what the code could be getting the value of when the exception occurs.

Interestingly, you can compile the code using .NET 1.1, and everything executes fine. Only when you compile using .NET 2.1 does the exception occur.

I don't know if there is a solution or work around to this, but I would be interested in any insight as to the cause.

+2  A: 

IIRC, there is also a warning about generics via reflection. I believe it calls out interfaces rather than concrete types, but the same may apply - in particular when using reflection.

Personally, I'm just dropping reflection when dealing with iPhone - it is easier. I'm still doing meta-programming, but I'm pre-generating regular code (on the full framework) which I then take over to MonoTouch. It seems to work pretty robustly.

Marc Gravell
No generics are being used at this point anywhere in the project code, otherwise I don't expect it would run under .NET 1.1, which is does. Furthermore, when I manually worked around the problem GetValue() call, the rest of the app runs fine, even though there are later Reflection SetValue() calls to the same property and those work without issue.The Limitations document linked above leads me to believe this should work, as it clearly state, "listing methods, listing properties, fetching attributes and values works just fine".I think I'll take your advice and move away from Reflection.
Michael Ryan
@Michael - `GetterAdapterFrame<Image, UnityEngine.Color>` looks generic to me
Marc Gravell
It sure does. I meant to say generics are not being used in *my* code. I'm guessing that the PropertyInfo.GetValue() method uses generics internally on the Mono/.NET 2.1 Framework, and that's causing the exception. Thanks!
Michael Ryan