![](https://habrastorage.org/files/50f/e10/b54/50fe10b546304038a74cd6cd84a95bea.jpg)
ç¹ã«ã6çš®é¡ã®åŒã³åºããæ€èšããŸãã
- ã€ã³ã¹ã¿ã³ã¹ã¡ãœãããšéçã¡ãœããã®çŽæ¥åŒã³åºãã
- ã³ã³ãã€ã«æããªã²ãŒããä»ããŠåŒã³åºããŸãã
- ä»®æ³ã¡ãœãããä»ããåŒã³åºãã
- ã€ã³ã¿ãŒãã§ã€ã¹ã¡ãœãããä»ããåŒã³åºãã
- ã©ã³ã¿ã€ã ããªã²ãŒããä»ããåŒã³åºã
- ãªãã¬ã¯ã·ã§ã³ã«ããææŠã
çæãããC ++ã³ãŒãã®ã¢ã¯ã·ã§ã³ãšãåã¿ã€ãã®åŒã³åºãã«é¢é£ããã³ã¹ãã«æ³šæãæããŸãã ç§ãèšã£ãããã«ãæ瀺ãããã³ãŒãã¯Unityã®å°æ¥ã®ããŒãžã§ã³ã§å€æŽãããå¯èœæ§ããããŸãã ããããåºæ¬ååã¯å€ãããŸããã
ã·ãªãŒãºã®ä»¥åã®èšäºïŒ
» IL2CPPã®æŠèŠã
» IL2CPPïŒçæãããã³ãŒãã®ãã¢ãŒã
» IL2CPPïŒçæãããã³ãŒãããããã°ããããã®ãã³ãã
ä»äºã®æºå
Windowsã§UnityããŒãžã§ã³5.0.1p4ã䜿çšããŠãWebGLã§ãããžã§ã¯ãããã«ãããŸãã ããããããšã§ãDevelopment Playerãªãã·ã§ã³ãæå¹ã«ããFullå€ãEnable Exceptionsã«èšå®ããŸãã ããŸããŸãªã¿ã€ãã®ã¡ãœããåŒã³åºããåæããããã«ãã€ã³ã¿ãŒãã§ãŒã¹ãšã¯ã©ã¹å®çŸ©ããå§ããŠãåã®èšäºã®ä¿®æ£ãããã¹ã¯ãªããã䜿çšããŸãã
[csharp] interface Interface { int MethodOnInterface(string question); } class Important : Interface { public int Method(string question) { return 42; } public int MethodOnInterface(string question) { return 42; } public static int StaticMethod(string question) { return 42; } } [/csharp]
ãããã®åŸã«ã¯ãå®æ°ãã£ãŒã«ããšããªã²ãŒãã¿ã€ããç¶ããŸãã
[csharp] private const string question = "What is the answer to the ultimate question of life, the universe, and everything?"; private delegate int ImportantMethodDelegate(string question); [/csharp]
æåŸã«ãç®çã®ã¡ãœãããšãå¿ èŠãªStartã¡ãœããïŒãã®å Žåã¯ç©ºïŒã瀺ããŸãã
[csharp] private void CallDirectly() { var important = ImportantFactory(); important.Method(question); } private void CallStaticMethodDirectly() { Important.StaticMethod(question); } private void CallViaDelegate() { var important = ImportantFactory(); ImportantMethodDelegate indirect = important.Method; indirect(question); } private void CallViaRuntimeDelegate() { var important = ImportantFactory(); var runtimeDelegate = Delegate.CreateDelegate(typeof (ImportantMethodDelegate), important, "Method"); runtimeDelegate.DynamicInvoke(question); } private void CallViaInterface() { Interface importantViaInterface = new Important(); importantViaInterface.MethodOnInterface(question); } private void CallViaReflection() { var important = ImportantFactory(); var methodInfo = typeof(Important).GetMethod("Method"); methodInfo.Invoke(important, new object[] {question}); } private static Important ImportantFactory() { var important = new Important(); return important; } void Start () {} [/csharp]
ããã§ããã¹ãŠã®æºåãæŽããŸããã ãšãã£ã¿ãŒãéããŠããéãçæãããC ++ã³ãŒãã¯Temp \ StagingArea \ Data \ il2cppOutputãã£ã¬ã¯ããªã«ããããšã«æ³šæããŠãã ããã ãŸããCtagsã䜿çšããŠã¿ã°ãã¡ã€ã«ãçæããã³ãŒãããã²ãŒã·ã§ã³ãç°¡åã«ããããšãå¿ããªãã§ãã ããã
ãã€ã¬ã¯ãã³ãŒã«
ã¡ãœããã®åŒã³åºãã¯ç°¡åã§ãã芧ã®ãšãããæãç°¡åãªæ¹æ³ãçŽæ¥åŒã³åºããŸãã ããã¯ãCallDirectlyã¡ãœããã®çæãããã³ãŒããã©ã®ããã«èŠãããã§ãïŒ
[cpp] Important_t1 * L_0 = HelloWorld_ImportantFactory_m15(NULL /*static, unused*/, /*hidden argument*/&HelloWorld_ImportantFactory_m15_MethodInfo); V_0 = L_0; Important_t1 * L_1 = V_0; NullCheck(L_1); Important_Method_m1(L_1, (String_t*) &_stringLiteral1, /*hidden argument*/&Important_Method_m1_MethodInfo); [/cpp]
æåŸã®è¡ã¯ã¡ãœããåŒã³åºãã§ãã C ++ã³ãŒãã§å®çŸ©ãããfreeé¢æ°ãåŒã³åºãã ãã§ããããšã«æ³šæããŠãã ããã åã®èšäºã§è¿°ã¹ãããã«ãIL2CPPã¯ã¡ã³ããŒé¢æ°ãä»®æ³é¢æ°ã䜿çšããŸãããããã¹ãŠã®ã¡ãœãããç¡æã®C ++é¢æ°ãšããŠçæããŸãã åæ§ã«ãéçã¡ãœãããžã®çŽæ¥åŒã³åºããæ©èœããŸãã CallStaticMethodDirectlyã¡ãœããã®çæã³ãŒãã¯æ¬¡ã®ãšããã§ãã
[cpp] Important_StaticMethod_m3(NULL /*static, unused*/, (String_t*) &_stringLiteral1, /*hidden argument*/&Important_StaticMethod_m3_MethodInfo); [/cpp]
éçã¡ãœããã®åŒã³åºãã¯ããªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ãäœæããã³åæåããå¿ èŠããªããããã³ã¹ããäœããšèšããŸãã ããããã¡ãœããåŒã³åºãèªäœã¯ãŸã£ããåãã§ãã å¯äžã®éãã¯ãéçé¢æ°ã®æåã®åŒæ°ã«å¯ŸããŠãIL2CPPã¯åžžã«NULLãæž¡ãããšã§ãã éçã¡ãœãããšã€ã³ã¹ã¿ã³ã¹ã¡ãœããã®åŒã³åºãã®éãã¯éåžžã«å°ããããããã®èšäºã§ã¯ããããèå¥ããŸãã
ã³ã³ãã€ã«æããªã²ãŒããä»ããåŒã³åºã
ããªã²ãŒããä»ããéæ¥åŒã³åºãã«ã¯ãç¬èªã®è©³çŽ°ããããŸãã ãŸããã³ã³ãã€ã«æã®ããªã²ãŒãã®æå³ãæ確ã«ããŸã-ã³ã³ãã€ã«æã«ããªããžã§ã¯ãã®ã©ã®ã€ã³ã¹ã¿ã³ã¹ããã©ã®ã¡ãœãããåŒã³åºããããããã§ã«ããã£ãŠããŸãã ãã®ã¿ã€ãã®ã³ãŒãã¯ãCallViaDelegateã¡ãœããã«ãããŸãã çæãããã³ãŒãã§ã¯ã次ã®ããã«ãªããŸãã
[cpp] // Get the object instance used to call the method. Important_t1 * L_0 = HelloWorld_ImportantFactory_m15(NULL /*static, unused*/, /*hidden argument*/&HelloWorld_ImportantFactory_m15_MethodInfo); V_0 = L_0; Important_t1 * L_1 = V_0; // Create the delegate. IntPtr_t L_2 = { &Important_Method_m1_MethodInfo }; ImportantMethodDelegate_t4 * L_3 = (ImportantMethodDelegate_t4 *)il2cpp_codegen_object_new (InitializedTypeInfo(&ImportantMethodDelegate_t4_il2cpp_TypeInfo)); ImportantMethodDelegate__ctor_m4(L_3, L_1, L_2, /*hidden argument*/&ImportantMethodDelegate__ctor_m4_MethodInfo); V_1 = L_3; ImportantMethodDelegate_t4 * L_4 = V_1; // Call the method NullCheck(L_4); VirtFuncInvoker1< int32_t, String_t* >::Invoke(&ImportantMethodDelegate_Invoke_m5_MethodInfo, L_4, (String_t*) &_stringLiteral1); [/cpp]
åŒã³åºãããã¡ãœããã¯ãå®éã«ã¯çæãããã³ãŒãã®äžéšã§ã¯ãªãããšã«æ³šæããŠãã ããã VirtFuncInvoker1 <int32_tãString_t *> :: Invokeã¡ãœããã¯ãå€ãè¿ãä»®æ³é¢æ°ïŒVirtFuncInvokerNïŒã䜿çšããŠil2cpp.exeãŠãŒãã£ãªãã£ã«ãã£ãŠçæãããGeneratedVirtualInvokers.hãã¡ã€ã«ã«ãããŸããNã¯åŒæ°ã®æ°ãæå³ããŸãã Invokeã¡ãœããã¯æ¬¡ã®ããã«ãªããŸãã
[cpp] template <typename R, typename T1> struct VirtFuncInvoker1 { typedef R (*Func)(void*, T1, MethodInfo*); static inline R Invoke (MethodInfo* method, void* obj, T1 p1) { VirtualInvokeData data = il2cpp::vm::Runtime::GetVirtualInvokeData (method, obj); return ((Func)data.methodInfo->method)(data.target, p1, data.methodInfo); } }; [/cpp]
GetVirtualInvokeDataåŒã³åºãã¯ããããŒãžã³ãŒãããçæãããvtableã§ä»®æ³ã¡ãœãããæ¢ãããã®ã¡ãœãããåŒã³åºããŸãã
VirtFuncInvokerNã¡ãœãããå®è£ ããããã«C ++ 11 å€æ°ãã³ãã¬ãŒãã䜿çšããªãã£ãã®ã¯ãªãã§ããïŒ ãã¹ãŠã¯ããã®å Žå圌ãã䟿å©ã«ãªã£ãã§ãããããšã瀺ããŠããŸãã ãã ããil2cpp.exeã«ãã£ãŠçæãããC ++ã³ãŒãã䜿çšããã«ã¯ãC ++ 11ã®ãã¹ãŠã®åŽé¢ããŸã ãµããŒãããŠããªãC ++ã³ã³ãã€ã©ãŒãå¿ èŠã«ãªããŸãããããã£ãŠãã³ã³ãã€ã©ãŒçšã«çæã³ãŒãã®å¥ã®ãã©ã³ããäœæãããšããã»ã¹ãè€éã«ãªãã ãã§ããããè¡ããªãããšã«ããŸããã
ãããããªãããã¯ä»®æ³ã¡ãœããåŒã³åºãã§ããïŒ CïŒã³ãŒãã§ã€ã³ã¹ã¿ã³ã¹ã¡ãœãããåŒã³åºããŸãããïŒ CïŒããªã²ãŒããéããŠãããè¡ãããšãå¿ããªãã§ãã ããã çæãããã³ãŒããããäžåºŠèŠãŠãã ããã åŒã³åºãããã¡ãœããã¯ãåŒæ°MethodInfo *ïŒã¡ãœããã¡ã¿ããŒã¿ïŒ-ImportantMethodDelegate_Invoke_m5_MethodInfoãä»ããŠæž¡ãããŸãã çæãããã³ãŒãã§ãImportantMethodDelegate_Invoke_m5ãšããã¡ãœãããæ€çŽ¢ãããšãåŒã³åºãããImportantMethodDelegateåã®InvokeãããŒãžã¡ãœããã«éãããããšãããããŸãã ããã¯ä»®æ³ã¡ãœããã§ãããããä»®æ³åŒã³åºããè¡ãå¿ èŠããããŸããImportantMethodDelegate_Invoke_m5é¢æ°ã¯ãCïŒã³ãŒãã®Methodãšããã¡ãœãããåŒã³åºããŸãã
ãã®ãããCïŒã³ãŒãã®ããããªå€æŽã«ãããåäžã®åŒã³åºãããç¡æã®C ++é¢æ°ãžã®ç§»è¡ããããŒãã«æ€çŽ¢ãå«ãè€æ°ã®åŒã³åºãã«ç§»è¡ããŸããã ãã ããããªã²ãŒããä»ããã¡ãœããã®åŒã³åºãã¯ãçŽæ¥ãããã¯ããã«é«äŸ¡ã§ãã ãšããã§ããã®çš®ã®åŒã³åºããæ€èšããéçšã§ãä»®æ³ã¡ãœãããéããŠåŒã³åºããã©ã®ããã«æ©èœãããã«ã€ããŠã話ããŸããã
ã€ã³ã¿ãŒãã§ã€ã¹ãä»ããåŒã³åºã
ã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠCïŒã§ã¡ãœãããåŒã³åºãããšãã§ããŸãã Il2cpp.exeã¯ãä»®æ³ã¡ãœããã®åŒã³åºããšåæ§ã«ãããã®åŒã³åºããè¡ããŸãã
[cpp] Important_t1 * L_0 = (Important_t1 *)il2cpp_codegen_object_new (InitializedTypeInfo(&Important_t1_il2cpp_TypeInfo)); Important__ctor_m0(L_0, /*hidden argument*/&Important__ctor_m0_MethodInfo); V_0 = L_0; Object_t * L_1 = V_0; NullCheck(L_1); InterfaceFuncInvoker1< int32_t, String_t* >::Invoke(&Interface_MethodOnInterface_m22_MethodInfo, L_1, (String_t*) &_stringLiteral1); [/cpp]
ãã®ã¡ãœããã¯ãGeneratedInterfaceInvokers.hãã¡ã€ã«ã§InterfaceFuncInvoker1 :: Invokeé¢æ°ã䜿çšããŠåŒã³åºãããããšã«æ³šæããŠãã ããã VirtFuncInvoker1ãšåæ§ã«ãInterfaceFuncInvoker1ã¯ã©ã¹ã¯ãilil2cppã®il2cpp :: vm :: Runtime :: GetInterfaceInvokeDataé¢æ°ã䜿çšããŠvtableãæ€çŽ¢ããŸãã
libil2cppã®ç°ãªãAPIã䜿çšããŠãã€ã³ã¿ãŒãã§ã€ã¹ã¡ãœãããä»ããåŒã³åºããšä»®æ³ã¡ãœãããä»ããåŒã³åºããè¡ãããã®ã¯ãªãã§ããïŒ InterfaceFuncInvoker1 :: Invokeé¢æ°ã®åŒã³åºãã¯ãåŒã³åºãããã¡ãœãããšãã®åŒæ°ã ãã§ãªããã€ã³ã¿ãŒãã§ã€ã¹ïŒãã®å Žåã¯L_1ïŒãæž¡ããŸãã ã€ã³ã¿ãŒãã§ã€ã¹ã®ã¡ãœããããªãã»ããã§åºå®ãããããã«ãvtableã¯ã¿ã€ãããšã«ä¿åãããŸãã ãããã£ãŠãil2cpp.exeã¯ãåŒã³åºãã¡ãœããã決å®ããããã®ã€ã³ã¿ãŒãã§ã€ã¹ãæäŸããå¿ èŠããããŸãã äžçªäžã®è¡ã¯ãä»®æ³ã¡ãœãããä»ããåŒã³åºããšã€ã³ã¿ãŒãã§ã€ã¹ãä»ããåŒã³åºãã¯ãIL2CPPã§ãåæ§ã«ã³ã¹ãããããããšã§ãã
ã©ã³ã¿ã€ã ããªã²ãŒããä»ããåŒã³åºã
Delegate.CreateDelegateã¡ãœããã䜿çšããŠãå®è¡æã«ããªã²ãŒããäœæããããšãã§ããŸãã ããã¯ã³ã³ãã€ã«æã«ããªã²ãŒããäœæããããšã«äŒŒãŠããŸãããå¥ã®é¢æ°ãåŒã³åºãå¿ èŠããããŸãã çæãããã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
[cpp] // Get the object instance used to call the method. Important_t1 * L_0 = HelloWorld_ImportantFactory_m15(NULL /*static, unused*/, /*hidden argument*/&HelloWorld_ImportantFactory_m15_MethodInfo); V_0 = L_0; // Create the delegate. IL2CPP_RUNTIME_CLASS_INIT(InitializedTypeInfo(&Type_t_il2cpp_TypeInfo)); Type_t * L_1 = Type_GetTypeFromHandle_m19(NULL /*static, unused*/, LoadTypeToken(&ImportantMethodDelegate_t4_0_0_0), /*hidden argument*/&Type_GetTypeFromHandle_m19_MethodInfo); Important_t1 * L_2 = V_0; Delegate_t12 * L_3 = Delegate_CreateDelegate_m20(NULL /*static, unused*/, L_1, L_2, (String_t*) &_stringLiteral2, /*hidden argument*/&Delegate_CreateDelegate_m20_MethodInfo); V_1 = L_3; Delegate_t12 * L_4 = V_1; // Call the method ObjectU5BU5D_t9* L_5 = ((ObjectU5BU5D_t9*)SZArrayNew(ObjectU5BU5D_t9_il2cpp_TypeInfo_var, 1)); NullCheck(L_5); IL2CPP_ARRAY_BOUNDS_CHECK(L_5, 0); ArrayElementTypeCheck (L_5, (String_t*) &_stringLiteral1); *((Object_t **)(Object_t **)SZArrayLdElema(L_5, 0)) = (Object_t *)(String_t*) &_stringLiteral1; NullCheck(L_4); Delegate_DynamicInvoke_m21(L_4, L_5, /*hidden argument*/&Delegate_DynamicInvoke_m21_MethodInfo); [/cpp]
ãã®ãããªããªã²ãŒããäœæããŠåæåããã«ã¯ãããã«å€ãã®ã³ãŒããå¿ èŠã§ãã ãããŠãã¡ãœããåŒã³åºãèªäœã¯ããé«äŸ¡ã§ãã æåã«ãã¡ãœããåŒæ°ã®é åãäœæããå¿ èŠããããŸãã 次ã«ãDelegateã€ã³ã¹ã¿ã³ã¹ããDynamicInvokeã¡ãœãããåŒã³åºããŸãã ãã®ã¡ãœããã¯ãã³ã³ãã€ã«æã®ããªã²ãŒããšåãããã«ãVirtFuncInvoker1 :: Invokeé¢æ°ãåŒã³åºãããšã«æ³šæããŠãã ããã ãããã£ãŠãã©ã³ã¿ã€ã ããªã²ãŒãã«ã¯ãå¥ã®é¢æ°åŒã³åºãã ãã§ãªããvtableã®è¿œå æ€çŽ¢ãå¿ èŠã§ãã
ãªãã¬ã¯ã·ã§ã³ã«ãã課é¡
åœç¶ã®ããšãªãããæãé«äŸ¡ãªã¡ãœããåŒã³åºãã®çš®é¡ã¯ãªãã¬ã¯ã·ã§ã³ã«ãããã®ã§ãã ããã¯ãCallViaReflectionã¡ãœããã®çæãããã³ãŒããã©ã®ããã«èŠãããã§ãïŒ
[cpp] // Get the object instance used to call the method. Important_t1 * L_0 = HelloWorld_ImportantFactory_m15(NULL /*static, unused*/, /*hidden argument*/&HelloWorld_ImportantFactory_m15_MethodInfo); V_0 = L_0; // Get the method metadata from the type via reflection. IL2CPP_RUNTIME_CLASS_INIT(InitializedTypeInfo(&Type_t_il2cpp_TypeInfo)); Type_t * L_1 = Type_GetTypeFromHandle_m19(NULL /*static, unused*/, LoadTypeToken(&Important_t1_0_0_0), /*hidden argument*/&Type_GetTypeFromHandle_m19_MethodInfo); NullCheck(L_1); MethodInfo_t * L_2 = (MethodInfo_t *)VirtFuncInvoker1< MethodInfo_t *, String_t* >::Invoke(&Type_GetMethod_m23_MethodInfo, L_1, (String_t*) &_stringLiteral2); V_1 = L_2; MethodInfo_t * L_3 = V_1; // Call the method. Important_t1 * L_4 = V_0; ObjectU5BU5D_t9* L_5 = ((ObjectU5BU5D_t9*)SZArrayNew(ObjectU5BU5D_t9_il2cpp_TypeInfo_var, 1)); NullCheck(L_5); IL2CPP_ARRAY_BOUNDS_CHECK(L_5, 0); ArrayElementTypeCheck (L_5, (String_t*) &_stringLiteral1); *((Object_t **)(Object_t **)SZArrayLdElema(L_5, 0)) = (Object_t *)(String_t*) &_stringLiteral1; NullCheck(L_3); VirtFuncInvoker2< Object_t *, Object_t *, ObjectU5BU5D_t9* >::Invoke(&MethodBase_Invoke_m24_MethodInfo, L_3, L_4, L_5); [/cpp]
å®è¡æããªã²ãŒããšåæ§ã«ãã¡ãœããåŒæ°ã®é åãäœæããå¿ èŠããããŸãã 次ã«ãä»®æ³ã¡ãœããMethodBase :: InvokeãåŒã³åºããŸãããã®ã¡ãœããã¯ãå¥ã®ä»®æ³é¢æ°ãåŒã³åºãMethodBase_Invoke_m24é¢æ°ã§ãã ãããŠãå¿ èŠãªã¡ãœããåŒã³åºããè¡ãããŸãã
ãããã«
ããã¯ãããã¡ã€ãªã³ã°ãšã¯ç°ãªããŸãããçæãããC ++ã³ãŒãã解æãããšãç¹å®ã®ã¡ãœããåŒã³åºãã«é¢é£ããã³ã¹ããããããç解ã§ããŸãã ããšãã°ãå®è¡æã®ããªã²ãŒããšãªãã¬ã¯ã·ã§ã³ãä»ããŠã¡ãœãããåŒã³åºãããšããå§ãããŸãã çç£æ§ãé«ããã«ã¯ãã§ããã°ãããã¡ã€ã©ãŒã䜿çšããŠãåæ段éã§ã³ã¹ãã枬å®ããŠãã ããã
il2cpp.exeã«ãã£ãŠçæãããã³ãŒãã®æé©åã«åŒãç¶ãåãçµãã§ãããããUnityã®æ¬¡ã®ããŒãžã§ã³ã§ã¯ããªã¹ããããŠããåŒã³åºãã®çš®é¡ãç°ãªã£ãŠèŠããå¯èœæ§ããããŸãã 次ã®èšäºã§ã¯ãæ±çšã¡ãœããã®å®è£ ãšãå®è¡å¯èœãã¡ã€ã«ãšçæãããã³ãŒãã®ãµã€ãºãåæžããæ¹æ³ã«ã€ããŠèª¬æããŸãã