unity3d关于IOS的AOT编译注意事项 ( AOT Exception Patterns and Hacks )

本文探讨了在iOS平台上使用AOT编译时遇到的各种问题及解决方案,重点关注了泛型、Lambda表达式、枚举等特性导致的问题,并提供了解决这些问题的方法。

Runnning on iOS sometimes raise runtime exception.

System.ExecutionEngineException: Attempting to JIT compile method

Generics is easy to cause a problem of AOT. UniRx use generics pipeline heavyly. But we cannnot be afraid if we know a pattern and counterplan. If you can't avoid AOT problem, please report to GitHub issues.

Interlocked.CompareExchange

// ExecutionEngineException: Attempting to JIT compile method '(wrapper native-to-managed)' while running with --aot-only
var a = "hoge";
Interlocked.CompareExchange<string>(ref a, "hugahuga", "hoge");

// It's Ok! CompareExchange(int, object, etc...) works.
object b = "hoge";
Interlocked.CompareExchange(ref b, "hugahuga", "hoge");

We can't use Interlocked.ComapreExchange[T]. (wrapper native-to-managed) exception needs MonoPInvokeCallback(see:Unity TroubleShooting), but Interlocked.CompareExchange[T] is internal, it's in mscorlib.dll. Alterenate, we can use Interlocked.CompareExchange(object).

Interface + GenericsMethod + Struct

The Three pair kills application.

public interface IMyInterface
{
    void MyMethod<T>(T x);
}

public class MyImpl : IMyInterface
{
    public void MyMethod<T>(T x)
    {
    }
}

IMyInterface intf = new MyImpl();
intf.MyMethod("hogehoge"); // ReferenceType is not dead

// System.ExecutionEngineException: Attempting to JIT compile method 'MyImpl:MyMethod<int> (int)' while running with --aot-only.
intf.MyMethod(100); // die

We can avoid by compiler hint.

// don't need call, write specified type anywhere. 
static void _CompilerHint()
{
    new MyImpl().MyMethod(default(int));
}

void Awake()
{
    IMyInterface intf = new MyImpl();
    intf.MyMethod(100); // Struct but not dead
}

Lambda + Generics + Struct

static void Death<T>()
{
    var act = new Action<T>(_ => { Debug.Log("hoge"); }); // not dead yet 

    // System.ExecutionEngineException: Attempting to JIT compile method '<Death>b__0<int> (int)' while running with --aot-only.
    act(default(T)); // die
}

// call with struct cause exception(If class run perfectly) 
Death<int>();

We can avoid by capture external value.

static void Death<T>()
{
    var _dummy = 0;
    var act = new Action<T>(_ => 
    {
        Debug.Log("hoge");

        _dummy.GetHashCode(); // capture external variable
    });

    act(default(T)); // not dead
}

Death<int>();

This technique is very useful for use UniRx because Rx(LINQ) use lambda heavily.

GenericsMethod + Struct + Class

This is complex and seriously problem.

public static void Run()
{
    // call by reference type cause exception
    // System.ExecutionEngineException: Attempting to JIT compile method 'Method2<int, object> ()' while running with --aot-only.
    Method1<object>();
}

public static void Method1<T1>()
{
    Method2<int, T1>(); // one side as value type
}

// Two type args and has return type
static string Method2<T1, T2>()
{
    return "";
}

Enum Array(List)

Enum is sometimes dangerous.

public enum MyEnum
{
    Apple
}

// System.ExecutionEngineException: Attempting to JIT compile method '(wrapper managed-to-managed) MyEnum[]:System.Collections.Generic.ICollection`1.CopyTo (UniRx.MyEnum[],int)' while running with --aot-only.
new[] { MyEnum.Apple }.ToArray();

We can avoid UniRx's Utility - AsSafeEnumerable.

new[] { MyEnum.Apple }.AsSafeEnumerable().ToArray();

AotSafe Utilities

Struct often cause storange behaviour. You can wrap IEnumerable/IObservable's element to Tuple1(as class wrapper).

Enumerable.Range(1, 10).WrapValueToClass(); // IEnumerable<Tuple<int>>
Observable.Range(1, 10).WrapValueToClass(); // IObservable<Tuple<int>>

LINQ and AOT

Some LINQ methods can't work on iOS. It's not LINQ limitation because mono 2.8 already fixed(such as this patch https://github.com/mono/mono/commit/071f495d6a4ce4951e2b2c9069586bd5bcde5fbb ). But Unity's mono runtime is 2.6. I post upgrade Enumerable.cs request on Unity Feedback. Upgrade Enumerable.cs for avoid AOT Problem of LINQ(Average etc...) .I'm glad to if you vote.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值