Open MrNerverDie opened 4 years ago
需要提前把BorderChange放到CustomBridge里头。
@chexiongsheng 需要提前把BorderChange放到CustomBridge里头的话,是说再打基础包的时候这些event就需要加上custombridge吗
打包的时候,就要加到custombridge列表
遇到一样的问题。il2cpp下,将delegate加到CustomBridge中也不起作用。一般的delegate加进去可以正常,一但做为event来使用,就会报System.Threading.Interlocked::CompareExchange这个的no AOT generated的错误。即使我在打基础包时,强行加了代码System.Threading.Interlocked.CompareExchange<对应的Delegate类>,补丁运行到这个event的时候还是会报错。有什么办法能修复吗 @chexiongsheng
CompareExchange
android版本的async多了个泛型调用,你用Patch,而不是Patch(Android)试试
CompareExchange
android版本的async多了个泛型调用,你用Patch,而不是Patch(Android)试试
我这边没有用到ascyn。也蛮试了一下用Patch,在Android(il2cpp)下仍然是会报这个错误:
01-12 09:42:04.718 E/Unity (14434): Exception: Attempting to call method 'System.Threading.Interlocked::CompareExchange<System.Action`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]>' for which no ahead of time (AOT) code was generated. 01-12 09:42:04.718 E/Unity (14434): at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 01-12 09:42:04.718 E/Unity (14434): at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 01-12 09:42:04.718 E/Unity (14434): at IFix.Core.ReflectionMethodInvoker.Invoke (IFix.Core.VirtualMachine virtualMachine, IFix.Core.Call& call, System.Boolean isInstantiate) [0x00000] in <00000000000000000000000000000000>:0 01-12 09:42:04.718 E/Unity (14434): at IFix.Core.ExternInvoker.Invoke (IFix.Core.VirtualMachine vm, IFix.Core.Call& call, System.Boolean isInstantiate) [0x00000] in <00000000000000000000000000000000>:0 01-12 09:42:04.718 E/Unity (14434): at IFix.Core.V 01-12 10:41:24.942 E/Unity (16474): Exception: Attempting to call method 'System.Threading.Interlocked::CompareExchange<TestPatchWithEventAssign+Invoke_Param0Int>' for which no ahead of time (AOT) code was generated. 01-12 10:41:24.942 E/Unity (16474): at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 01-12 10:41:24.942 E/Unity (16474): at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 01-12 10:41:24.942 E/Unity (16474): at IFix.Core.ReflectionMethodInvoker.Invoke (IFix.Core.VirtualMachine virtualMachine, IFix.Core.Call& call, System.Boolean isInstantiate) [0x00000] in <00000000000000000000000000000000>:0 01-12 10:41:24.942 E/Unity (16474): at IFix.Core.ExternInvoker.Invoke (IFix.Core.VirtualMachine vm, IFix.Core.Call& call, System.Boolean isInstantiate) [0x00000] in <00000000000000000000000000000000>:0 01-12 10:41:24.942 E/Unity (16474): at IFix.Core.VirtualMachine.Execute (IFix.Core.Instruction pc, IFix.Core.Value a
相应的引起报错的地方:
TestPatchWithEventAssign.onInvoke_Param0String += event_invoke_param0string;
TestPatchWithEventAssign.onInvoke_Param0String -= event_invoke_param0string;
我的CustomBridge配置如下,应该是没错的吧
[IFix.CustomBridge]
public static class AdditionalBridge
{
private static List<Type> bridge = new List<Type>() {
typeof(INativeInterface), //* Need for TEST_NEW_CLASS_IMPLEMENT_NATIVE_INTERFACE
typeof(System.Action<int>), //* Need for TEST_ADD_NEW_LAMBDA_CLASS
typeof(TestPatchWithEventAssign.Invoke_Param0Int),
typeof(System.Action<string>),
};
}
CompareExchange
跟CustomBridge没关系,怎么配都没用。报错表示指令里有个对一个需要AOT的泛型方法调用。
CompareExchange
跟CustomBridge没关系,怎么配都没用。报错表示指令里有个对一个需要AOT的泛型方法调用。
我反编译出来看过,
[Preserve]
public static event Invoke_Param0Int onInvoke_Param0Int;
[Preserve]
public static event Action<string> onInvoke_Param0String;
是两个event事件生成出来的add函数和remove函数,它们的指令里会有报错的那个方法(CompareExchange)。
IL_001c: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class TestPatchWithEventAssign/Invoke_Param0Int>(!!0&, !!0, !!0)
IL_001c: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class [mscorlib]System.Action`1<string>>(!!0&, !!0, !!0)
有什么办法可以解决掉这个AOT报错吗? 我看它报错说"no ahead of time (AOT) code was generated", 所以尝试过在原生代码里面强行调用一次它会生成的函数,也是没什么用。感觉没法"generate"这个"ahead of time (AOT) code"的样子
public static void NoOneCallThisFunc_DefineForAOT()
{
// System_Threading_Interlocked_CompareExchange<System.Action<string>>();
// System_Threading_Interlocked_CompareExchange<Invoke_Param0Int>();
{
var a = default(System.Action<string>);
System.Threading.Interlocked.CompareExchange(ref a, a, a);
}
{
var a = default(Invoke_Param0Int);
System.Threading.Interlocked.CompareExchange(ref a, a, a);
}
}
据说你别Patch(Android),直接用patch就没这指令。
据说你别Patch(Android),直接用patch就没这指令。
我试过的,直接用Patch,运行起来也是会碰到这个指令而报错。跟用Patch(Android)一样的报错。 我这边,这个指令在Editor下的Assembly-CSharp.dll里面就是会存在。不知道是不是跟什么环境配置有关系
不管是加入CustomBridge还是Patch选项,都不能解决问题 这里的关键是il2cpp之后,interlocked.CompareExchange函数在cpp层的实现并没有反射机制,直接变成了CompareExchangeImpl,所以运行时在尝试调用泛型的CompareExchange就会报错。这也是为什么Unity编辑器端OK但是Android就报错的原因。
解决办法1,适用于用户这边,改用delegate而不用event,或者在event里面手动添加add/remove,都可以去除调用CompareExchange这一条指令,但是这会使语义降级,把线程安全的变成线程不安全的。(因为CompareExchange是.net实现CAS机制的函数)
解决办法2,需要修改InjectFix,inject时自己增加一层wrapper函数,间接调用对应的interlocked.CompareExchange函数,并显式化这一层wrapper函数(防止被il2cpp裁剪);同时生成patch指令时把对应的对interlocked.CompareExchange的callExtern调用转到wrapper函数中
至于为什么il2cpp不把CompareExchange也增加反射机制,我理解这是il2cpp的优化机制,毕竟它也想不到会有InjectFix这样增加虚拟机调用神奇的用法。
作者有没有兴趣加个QQ我们细聊🤩
CompareExchange
跟CustomBridge没关系,怎么配都没用。报错表示指令里有个对一个需要AOT的泛型方法调用。
我反编译出来看过,
[Preserve] public static event Invoke_Param0Int onInvoke_Param0Int; [Preserve] public static event Action<string> onInvoke_Param0String;
是两个event事件生成出来的add函数和remove函数,它们的指令里会有报错的那个方法(CompareExchange)。
IL_001c: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class TestPatchWithEventAssign/Invoke_Param0Int>(!!0&, !!0, !!0) IL_001c: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class [mscorlib]System.Action`1<string>>(!!0&, !!0, !!0)
有什么办法可以解决掉这个AOT报错吗? 我看它报错说"no ahead of time (AOT) code was generated", 所以尝试过在原生代码里面强行调用一次它会生成的函数,也是没什么用。感觉没法"generate"这个"ahead of time (AOT) code"的样子
public static void NoOneCallThisFunc_DefineForAOT() { // System_Threading_Interlocked_CompareExchange<System.Action<string>>(); // System_Threading_Interlocked_CompareExchange<Invoke_Param0Int>(); { var a = default(System.Action<string>); System.Threading.Interlocked.CompareExchange(ref a, a, a); } { var a = default(Invoke_Param0Int); System.Threading.Interlocked.CompareExchange(ref a, a, a); } }
不管是加入CustomBridge还是Patch选项,都不能解决问题 这里的关键是il2cpp之后,interlocked.CompareExchange函数在cpp层的实现并没有反射机制,直接变成了CompareExchangeImpl,所以运行时在尝试调用泛型的CompareExchange就会报错。这也是为什么Unity编辑器端OK但是Android就报错的原因。
解决办法1,适用于用户这边,改用delegate而不用event,或者在event里面手动添加add/remove,都可以去除调用CompareExchange这一条指令,但是这会使语义降级,把线程安全的变成线程不安全的。(因为CompareExchange是.net实现CAS机制的函数)
解决办法2,需要修改InjectFix,inject时自己增加一层wrapper函数,间接调用对应的interlocked.CompareExchange函数,并显式化这一层wrapper函数(防止被il2cpp裁剪);同时生成patch指令时把对应的对interlocked.CompareExchange的callExtern调用转到wrapper函数中
至于为什么il2cpp不把CompareExchange也增加反射机制,我理解这是il2cpp的优化机制,毕竟它也想不到会有InjectFix这样增加虚拟机调用神奇的用法。
作者有没有兴趣加个QQ我们细聊🤩
额,我有点没太理解,这里不应该是Patch的方法体以反射的形式调用event的默认add方法么,没有直接调用Interlocked.CompareExchange啊
额,我有点没太理解,这里不应该是Patch的方法体以反射的形式调用event的默认add方法么,没有直接调用Interlocked.CompareExchange啊
编译后调用了什么就调用什么。编译器有时会帮你干些事情。
报错信息: ExecutionEngineException: Attempting to call method 'System.Threading.Interlocked::CompareExchange<MoleMole.LevelBorder+BorderChange>' for which no ahead of time (AOT) code was generated. 06-12 19:34:17.195 10092 10156 E Unity : at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 06-12 19:34:17.195 10092 10156 E Unity : at IFix.Core.ReflectionMethodInvoker.Invoke (IFix.Core.VirtualMachine virtualMachine, IFix.Core.Call& call, System.Boolean isInstantiate) [0x00000] in <00000000000000000000000000000000>:0 06-12 19:34:17.195 10092 10156 E Unity : at IFix.Core.VirtualMachine.Execute (IFix.Core.Instruction pc, IFix.Core.Value argumentBase, System.Object[] managedStack, IFix.Core.Value* evaluationStackBase, System.Int32 argsCount, System.Int32 methodIndex, System.Int32 refCount, IFix.Core.Value* topWriteBack) [0x00000] in <00000000000000000000000000000000>:0 06-12 19:34:17.195 10092 10156 E Unity : at IFix.Core.VirtualMachine.Execute (IFix.Core.Instruction pc,
相应的报错位置
MonoBasicLevel.levelManager.GetLevelBorder().OnGetLevelBorder -= OnGetLevelBorder
其中OnGetLevelBorder是一个定义有ref参数的event ``