Ei kuvausta
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

036-CSharpFunctionPointers.cs 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Doesn't work with IL2CPP yet - waiting for Unity fix to land.
  2. #if BURST_INTERNAL //|| UNITY_2021_2_OR_NEWER
  3. using System;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. using Unity.Burst;
  7. using UnityBenchShared;
  8. namespace Burst.Compiler.IL.Tests
  9. {
  10. [BurstCompile]
  11. internal class TestCSharpFunctionPointers
  12. {
  13. [TestCompiler]
  14. public static unsafe int TestCSharpFunctionPointer()
  15. {
  16. delegate* unmanaged[Cdecl]<int, int> callback = &TestCSharpFunctionPointerCallback;
  17. return TestCSharpFunctionPointerHelper(callback);
  18. }
  19. private static unsafe int TestCSharpFunctionPointerHelper(delegate* unmanaged[Cdecl]<int, int> callback)
  20. {
  21. return callback(5);
  22. }
  23. [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
  24. [BurstCompile]
  25. private static int TestCSharpFunctionPointerCallback(int value) => value + 1;
  26. [TestCompiler]
  27. public static unsafe int TestCSharpFunctionPointerCastingParameterPtrFromVoid()
  28. {
  29. delegate* unmanaged[Cdecl]<void*, int> callback = &TestCSharpFunctionPointerCallbackVoidPtr;
  30. delegate* unmanaged[Cdecl]<int*, int> callbackCasted = callback;
  31. int i = 5;
  32. return callbackCasted(&i);
  33. }
  34. [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
  35. [BurstCompile]
  36. private static unsafe int TestCSharpFunctionPointerCallbackVoidPtr(void* value) => *((int*)value) + 1;
  37. [TestCompiler]
  38. public static unsafe int TestCSharpFunctionPointerCastingParameterPtrToVoid()
  39. {
  40. delegate* unmanaged[Cdecl]<int*, int> callback = &TestCSharpFunctionPointerCallbackIntPtr;
  41. delegate* unmanaged[Cdecl]<void*, int> callbackCasted = (delegate* unmanaged[Cdecl]<void*, int>)callback;
  42. int i = 5;
  43. return callbackCasted(&i);
  44. }
  45. [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
  46. [BurstCompile]
  47. private static unsafe int TestCSharpFunctionPointerCallbackIntPtr(int* value) => *value + 1;
  48. [TestCompiler]
  49. public static unsafe int TestCSharpFunctionPointerCastingToAndFromVoidPtr()
  50. {
  51. delegate* unmanaged[Cdecl]<int*, int> callback = &TestCSharpFunctionPointerCallbackIntPtr;
  52. void* callbackAsVoidPtr = callback;
  53. delegate* unmanaged[Cdecl]<int*, int> callbackCasted = (delegate* unmanaged[Cdecl]<int*, int>)callbackAsVoidPtr;
  54. int i = 5;
  55. return callbackCasted(&i);
  56. }
  57. public struct CSharpFunctionPointerProvider : IArgumentProvider
  58. {
  59. public unsafe object Value
  60. {
  61. get
  62. {
  63. delegate* unmanaged[Cdecl]<int, int> callback = &TestCSharpFunctionPointerCallback;
  64. return (IntPtr)callback;
  65. }
  66. }
  67. }
  68. [TestCompiler(typeof(CSharpFunctionPointerProvider))]
  69. public static unsafe int TestCSharpFunctionPointerPassedInFromOutside(IntPtr callbackAsIntPtr)
  70. {
  71. delegate* unmanaged[Cdecl]<int, int> callback = (delegate* unmanaged[Cdecl]<int, int>)callbackAsIntPtr;
  72. return TestCSharpFunctionPointerHelper(callback);
  73. }
  74. private struct TestCSharpFunctionPointerWithStructParameterStruct
  75. {
  76. public int X;
  77. }
  78. [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
  79. [BurstCompile]
  80. private static int TestCSharpFunctionPointerWithStructParameterCallback(TestCSharpFunctionPointerWithStructParameterStruct value) => value.X + 1;
  81. public struct CSharpFunctionPointerWithStructParameterProvider : IArgumentProvider
  82. {
  83. public unsafe object Value
  84. {
  85. get
  86. {
  87. delegate* unmanaged[Cdecl]<TestCSharpFunctionPointerWithStructParameterStruct, int> callback = &TestCSharpFunctionPointerWithStructParameterCallback;
  88. return (IntPtr)callback;
  89. }
  90. }
  91. }
  92. [TestCompiler(typeof(CSharpFunctionPointerWithStructParameterProvider))]
  93. public static unsafe int TestCSharpFunctionPointerPassedInFromOutsideWithStructParameter(IntPtr untypedFp)
  94. {
  95. return TestHashingFunctionPointerTypeHelper((delegate* unmanaged[Cdecl]<TestCSharpFunctionPointerWithStructParameterStruct, int>)untypedFp);
  96. }
  97. private static unsafe int TestHashingFunctionPointerTypeHelper(delegate* unmanaged[Cdecl]<TestCSharpFunctionPointerWithStructParameterStruct, int> fp)
  98. {
  99. return fp(new TestCSharpFunctionPointerWithStructParameterStruct { X = 42 });
  100. }
  101. [TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_CalliNonCCallingConventionNotSupported)]
  102. public static unsafe int TestCSharpFunctionPointerInvalidCallingConvention()
  103. {
  104. delegate*<int, int> callback = &TestCSharpFunctionPointerInvalidCallingConventionCallback;
  105. return callback(5);
  106. }
  107. [BurstCompile]
  108. private static int TestCSharpFunctionPointerInvalidCallingConventionCallback(int value) => value + 1;
  109. [TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_FunctionPointerMethodMissingBurstCompileAttribute)]
  110. public static unsafe int TestCSharpFunctionPointerMissingBurstCompileAttribute()
  111. {
  112. delegate* unmanaged[Cdecl]<int, int> callback = &TestCSharpFunctionPointerCallbackMissingBurstCompileAttribute;
  113. return callback(5);
  114. }
  115. [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
  116. private static int TestCSharpFunctionPointerCallbackMissingBurstCompileAttribute(int value) => value + 1;
  117. #if BURST_TESTS_ONLY
  118. [DllImport("burst-dllimport-native")]
  119. private static extern unsafe int callFunctionPointer(delegate* unmanaged[Cdecl]<int, int> f);
  120. // Ignored on wasm since dynamic linking is not supported at present.
  121. // Override result on Mono because it throws a StackOverflowException for some reason related to the function pointer.
  122. // We should use OverrideResultOnMono, but OverrideResultOnMono still runs the managed version, which causes a crash,
  123. // so we use OverrideManagedResult.
  124. [TestCompiler(IgnoreOnPlatform = Backend.TargetPlatform.Wasm, OverrideManagedResult = 43)]
  125. public static unsafe int TestPassingFunctionPointerToNativeCode()
  126. {
  127. return callFunctionPointer(&TestCSharpFunctionPointerCallback);
  128. }
  129. #endif
  130. }
  131. }
  132. // This attribute is also included in com.unity.burst/Tests/Runtime/FunctionPointerTests.cs,
  133. // so we want to exclude it here when we're running inside Unity otherwise we'll get a
  134. // duplicate definition error.
  135. #if BURST_TESTS_ONLY
  136. // UnmanagedCallersOnlyAttribute is new in .NET 5.0. This attribute is required
  137. // when you declare an unmanaged function pointer with an explicit calling convention.
  138. // Fortunately, Roslyn lets us declare the attribute class ourselves, and it will be used.
  139. // Users will need this same declaration in their own projects, in order to use
  140. // C# 9.0 function pointers.
  141. namespace System.Runtime.InteropServices
  142. {
  143. [AttributeUsage(System.AttributeTargets.Method, Inherited = false)]
  144. public sealed class UnmanagedCallersOnlyAttribute : Attribute
  145. {
  146. public Type[] CallConvs;
  147. }
  148. }
  149. #endif
  150. #endif