Version: 2020.2
言語: 日本語
IL2CPP によるマネージスタックトレース
マネージコードストリッピング

スクリプトの制限

Unity strives to provide a common scripting API and experience across all platforms it supports. However, some platforms have inherent restrictions. To help you understand these restrictions and support cross-platform code, the following table describes which restrictions apply to each platform and scripting backend:

.NET 4.x 同等のスクリプティングランタイム

プラットフォーム (スクリプトバックエンド) 事前コンパイル スレッドなし .NET Core クラスライブラリサブセット
Android (IL2CPP)
Android (Mono)
iOS (IL2CPP)
PlayStation 4 (IL2CPP)
PlayStation Vita (IL2CPP)
スタンドアロン (IL2CPP)
スタンドアロン (Mono)
Switch (IL2CPP)
ユニバーサル Windows プラットフォーム (IL2CPP)
ユニバーサル Windows プラットフォーム (.NET)
WebGL (IL2CPP)
WiiU (Mono)
XBox One (IL2CPP)

事前 (AOT) コンパイル

Some platforms do not allow runtime code generation. Therefore, any managed code which depends upon just-in-time (JIT) compilation on the target device will fail. Instead, you need to compile all of the managed code ahead-of-time (AOT). Often, this distinction doesn’t matter, but in a few specific cases, AOT platforms require additional consideration.

System.Reflection.Emit

事前 (AOT) コンパイルが必要なプラットフォームには、System.Reflection.Emit 名前空間のメソッドを実装することができません。それ以外の System.Reflection は使用可能です。ただし、リフレクションを通して使用されるコードがランタイムに存在する必要があることをコンパイラーが推測可能でなくてはなりません。

シリアライズ

AOT platforms can encounter issues with serialization and deserlization due to the use of reflection. If a type or method is only used via reflection as part of serialization or deserialization, the AOT compiler cannot detect that the code needs to be generated for the type or method.

ジェネリックな仮想メソッド

Generic methods require the compiler to do some additional work to expand the code written by the developer to the code executed on the device. For example, you need different code for List with an int or a double. In the presence of virtual methods, where behavior is determined at runtime rather than compile time, the compiler can easily require runtime code generation in places where it is not entirely obvious from the source code.

以下のようなコードがあるとします。JIT プラットフォームでは、意図した通りに動きます (“Message value: Zero” のメッセージがコンソールに 1 回出力されます)。

using UnityEngine;
using System;

public class AOTProblemExample : MonoBehaviour, IReceiver
{
    public enum AnyEnum 
    {
        Zero,
        One,
    }

    void Start() 
    {
        //AOT 問題を警告するには 、manager のタイプは 
        // Manager ではなく、IManager の必要があります。
        IManager manager = new Manager();
        manager.SendMessage(this, AnyEnum.Zero);
    }

    public void OnMessage<T>(T value) 
    {
        Debug.LogFormat("Message value: {0}", value);
    }
}

public class Manager : IManager 
{
    public void SendMessage<T>(IReceiver target, T value) {
        target.OnMessage(value);
    }
}

public interface IReceiver
{
    void OnMessage<T>(T value);
}

public interface IManager 
{
    void SendMessage<T>(IReceiver target, T value);
}

しかし、このコードを IL2CPP スクリプティングバックエンドを持つ AOT (事前) プラットフォームで実行すると、この例外が発生します。

ExecutionEngineException: Attempting to call method 'AOTProblemExample::OnMessage&lt;AOTProblemExample+AnyEnum&gt;' for which no ahead of time (AOT) code was generated.
  at Manager.SendMessage[T] (IReceiver target, .T value) [0x00000] in &lt;filename unknown&gt;:0 
  at AOTProblemExample.Start () [0x00000] in &lt;filename unknown&gt;:0

同様に、Mono スクリプティングバックエンドでは、以下のような類似の例外が発生します。


  ExecutionEngineException: Attempting to JIT compile method 'Manager:SendMessage<AOTProblemExample/AnyEnum> (IReceiver,AOTProblemExample/AnyEnum)' while running with --aot-only.
    at AOTProblemExample.Start () [0x00000] in <filename unknown>:0

The AOT compiler does not realize that it should generate code for the generic method OnMessage with a T of AnyEnum, so it continues, skipping this method. When that method is called, and the runtime can’t find the proper code to execute, it returns this error message.

To work around an AOT issue like this, you can force the compiler to generate the proper code. You can add the following example method to the AOTProblemExample class:

public void UsedOnlyForAOTCodeGeneration() 
{
    // IL2CPPはこの行だけ必要です。
    OnMessage(AnyEnum.Zero);

    // Monoにもこの行が必要です。IManager インターフェース
    // ではなくManager 上で直接呼び出します。
    new Manager().SendMessage(null, AnyEnum.Zero);

    // 例外をもつため、このメソッドが呼び出されたかどうかを確認することができます。
    throw new InvalidOperationException("This method is used for AOT code generation only. Do not call it at runtime.");
}

When the compiler encounters the explicit call to OnMessage with a T of AnyEnum, it generates the proper code for the runtime to execute. The method UsedOnlyForAOTCodeGeneration does not need to be called; it just needs to exist for the compiler to see it.

ネイティブコードからのマネージメソッドの呼び出し

Managed methods that need to be marshaled to a C function pointer so that they can be called from native code have a few restructions on AOT platforms:

  • マネージメソッドは静的メソッドでなければなりません。
  • マネージメソッドは、MonoPInvokeCallback 属性を持つ必要があります。

スレッド不可

Some platforms do not support the use of threads, so any managed code that uses the System.Threading namespace will fail at runtime. Also, some parts of the .NET class libraries implicitly depend upon threads. An often-used example is the System.Timers.Timer class, which depends on support for threads.

例外フィルター

IL2CPP は C# の例外フィルターをサポートしていません。例外フィルターに依存するコードは、適切な catch ブロックに変更する必要があります。

TypedReference

IL2CPP は、System.TypedReference 型や __makeref C# キーワードには対応していません。


  • Samsung TV サポートを削除
  • .Net 3.5 スクリプティングランタイムは、2018.3 では非推奨です。 NewIn20183
IL2CPP によるマネージスタックトレース
マネージコードストリッピング