Keine Beschreibung
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

BurstCompiler.cs 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Reflection;
  5. using System.Runtime.InteropServices;
  6. #if !UNITY_DOTSPLAYER && !NET_DOTS
  7. using UnityEngine.Scripting;
  8. using System.Linq;
  9. #endif
  10. using System.Text;
  11. namespace Unity.Burst
  12. {
  13. /// <summary>
  14. /// The burst compiler runtime frontend.
  15. /// </summary>
  16. ///
  17. public static class BurstCompiler
  18. {
  19. /// <summary>
  20. /// Check if the LoadAdditionalLibrary API is supported by the current version of Unity
  21. /// </summary>
  22. /// <returns>True if the LoadAdditionalLibrary API can be used by the current version of Unity</returns>
  23. public static bool IsLoadAdditionalLibrarySupported()
  24. {
  25. return IsApiAvailable("LoadBurstLibrary");
  26. }
  27. #if !UNITY_DOTSPLAYER && !NET_DOTS
  28. #if UNITY_EDITOR
  29. static unsafe BurstCompiler()
  30. {
  31. // Store pointers to Log and Compile callback methods.
  32. // For more info about why we need to do this, see comments in CallbackStubManager.
  33. string GetFunctionPointer<TDelegate>(TDelegate callback)
  34. {
  35. GCHandle.Alloc(callback); // Ensure delegate is never garbage-collected.
  36. var callbackFunctionPointer = Marshal.GetFunctionPointerForDelegate(callback);
  37. return "0x" + callbackFunctionPointer.ToInt64().ToString("X16");
  38. }
  39. EagerCompileCompileCallbackFunctionPointer = GetFunctionPointer<CompileCallbackDelegate>(EagerCompileCompileCallback);
  40. EagerCompileLogCallbackFunctionPointer = GetFunctionPointer<LogCallbackDelegate>(EagerCompileLogCallback);
  41. #if UNITY_2020_1_OR_NEWER
  42. ProgressCallbackFunctionPointer = GetFunctionPointer<ProgressCallbackDelegate>(ProgressCallback);
  43. ProfileBeginCallbackFunctionPointer = GetFunctionPointer<ProfileBeginCallbackDelegate>(ProfileBeginCallback);
  44. ProfileEndCallbackFunctionPointer = GetFunctionPointer<ProfileEndCallbackDelegate>(ProfileEndCallback);
  45. #endif
  46. }
  47. #endif
  48. #if BURST_INTERNAL
  49. [ThreadStatic]
  50. public static Func<object, IntPtr> InternalCompiler;
  51. #endif
  52. /// <summary>
  53. /// Internal variable setup by BurstCompilerOptions.
  54. /// </summary>
  55. #if BURST_INTERNAL
  56. [ThreadStatic] // As we are changing this boolean via BurstCompilerOptions in btests and we are running multithread tests
  57. // we would change a global and it would generate random errors, so specifically for btests, we are using a TLS.
  58. public
  59. #else
  60. internal
  61. #endif
  62. static bool _IsEnabled;
  63. /// <summary>
  64. /// Gets a value indicating whether Burst is enabled.
  65. /// </summary>
  66. #if UNITY_EDITOR || BURST_INTERNAL
  67. public static bool IsEnabled => _IsEnabled;
  68. #else
  69. public static bool IsEnabled => _IsEnabled && BurstCompilerHelper.IsBurstGenerated;
  70. #endif
  71. /// <summary>
  72. /// Gets the global options for the burst compiler.
  73. /// </summary>
  74. public static readonly BurstCompilerOptions Options = new BurstCompilerOptions(true);
  75. #if UNITY_2019_3_OR_NEWER
  76. /// <summary>
  77. /// Sets the execution mode for all jobs spawned from now on.
  78. /// </summary>
  79. /// <param name="mode">Specifiy the required execution mode</param>
  80. public static void SetExecutionMode(BurstExecutionEnvironment mode)
  81. {
  82. Burst.LowLevel.BurstCompilerService.SetCurrentExecutionMode((uint)mode);
  83. }
  84. /// <summary>
  85. /// Retrieve the current execution mode that is configured.
  86. /// </summary>
  87. /// <returns>Currently configured execution mode</returns>
  88. public static BurstExecutionEnvironment GetExecutionMode()
  89. {
  90. return (BurstExecutionEnvironment)Burst.LowLevel.BurstCompilerService.GetCurrentExecutionMode();
  91. }
  92. #endif
  93. /// <summary>
  94. /// Compile the following delegate with burst and return a new delegate.
  95. /// </summary>
  96. /// <typeparam name="T"></typeparam>
  97. /// <param name="delegateMethod"></param>
  98. /// <returns></returns>
  99. /// <remarks>NOT AVAILABLE, unsafe to use</remarks>
  100. internal static unsafe T CompileDelegate<T>(T delegateMethod) where T : class
  101. {
  102. // We have added support for runtime CompileDelegate in 2018.2+
  103. void* function = Compile(delegateMethod, false);
  104. object res = System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer((IntPtr)function, delegateMethod.GetType());
  105. return (T)res;
  106. }
  107. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  108. private static void VerifyDelegateIsNotMulticast<T>(T delegateMethod) where T : class
  109. {
  110. var delegateKind = delegateMethod as Delegate;
  111. if (delegateKind.GetInvocationList().Length > 1)
  112. {
  113. throw new InvalidOperationException($"Burst does not support multicast delegates, please use a regular delegate for `{delegateMethod}'");
  114. }
  115. }
  116. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  117. private static void VerifyDelegateHasCorrectUnmanagedFunctionPointerAttribute<T>(T delegateMethod) where T : class
  118. {
  119. var attrib = delegateMethod.GetType().GetCustomAttribute<System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute>();
  120. if (attrib == null || attrib.CallingConvention != CallingConvention.Cdecl)
  121. {
  122. #if !BURST_INTERNAL
  123. UnityEngine.Debug.LogWarning($"The delegate type {delegateMethod.GetType().FullName} should be decorated with [UnmanagedFunctionPointer(CallingConvention.Cdecl)] to ensure runtime interoperabilty between managed code and Burst-compiled code.");
  124. #endif
  125. }
  126. }
  127. /// <summary>
  128. /// Compile an IL Post-Processed method.
  129. /// </summary>
  130. /// <param name="burstMethodHandle">The Burst method to compile.</param>
  131. /// <param name="managedMethodHandle">The fallback managed method to use.</param>
  132. /// <param name="delegateTypeHandle">The type of the delegate used to execute these methods.</param>
  133. /// <returns>A token that must be passed to <see cref="GetILPPMethodFunctionPointer"/> to get an actual executable function pointer.</returns>
  134. public static unsafe IntPtr CompileILPPMethod(RuntimeMethodHandle burstMethodHandle, RuntimeMethodHandle managedMethodHandle, RuntimeTypeHandle delegateTypeHandle)
  135. {
  136. if (burstMethodHandle.Value == IntPtr.Zero)
  137. {
  138. throw new ArgumentNullException(nameof(burstMethodHandle));
  139. }
  140. if (managedMethodHandle.Value == IntPtr.Zero)
  141. {
  142. throw new ArgumentNullException(nameof(managedMethodHandle));
  143. }
  144. if (delegateTypeHandle.Value == IntPtr.Zero)
  145. {
  146. throw new ArgumentNullException(nameof(delegateTypeHandle));
  147. }
  148. OnCompileILPPMethod?.Invoke();
  149. var burstMethod = (MethodInfo)MethodBase.GetMethodFromHandle(burstMethodHandle);
  150. var managedMethod = (MethodInfo)MethodBase.GetMethodFromHandle(managedMethodHandle);
  151. var delegateType = Type.GetTypeFromHandle(delegateTypeHandle);
  152. var managedFallbackDelegate = Delegate.CreateDelegate(delegateType, managedMethod);
  153. return (IntPtr)Compile(new FakeDelegate(burstMethod), burstMethod, isFunctionPointer: true, managedFallbackDelegateObj: managedFallbackDelegate);
  154. }
  155. internal static Action OnCompileILPPMethod;
  156. /// <summary>
  157. /// For a previous call to <see cref="CompileILPPMethod"/>, get the actual executable function pointer.
  158. /// </summary>
  159. /// <param name="ilppMethod">The result of a previous call to <see cref="CompileILPPMethod"/>.</param>
  160. /// <returns>A pointer into an executable region, for running the function pointer.</returns>
  161. public static unsafe void* GetILPPMethodFunctionPointer(IntPtr ilppMethod)
  162. {
  163. if (ilppMethod == IntPtr.Zero)
  164. {
  165. throw new ArgumentNullException(nameof(ilppMethod));
  166. }
  167. // If we are in the editor, we need to route a command to the compiler to start compiling the deferred ILPP compilation.
  168. // Otherwise if we're in Burst's internal testing, or in a player build, we already actually have the actual executable
  169. // pointer address, and we just return that.
  170. #if UNITY_EDITOR
  171. var result = SendCommandToCompiler(BurstCompilerOptions.CompilerCommandILPPCompilation, "0x" + ilppMethod.ToInt64().ToString("X16"));
  172. return new IntPtr(Convert.ToInt64(result, 16)).ToPointer();
  173. #else
  174. return ilppMethod.ToPointer();
  175. #endif
  176. }
  177. /// <summary>
  178. /// DO NOT USE - deprecated.
  179. /// </summary>
  180. /// <param name="handle">A runtime method handle.</param>
  181. /// <returns>Nothing.</returns>
  182. [Obsolete("This method will be removed in a future version of Burst")]
  183. public static unsafe void* CompileUnsafeStaticMethod(RuntimeMethodHandle handle)
  184. {
  185. throw new NotImplementedException();
  186. }
  187. /// <summary>
  188. /// Compile the following delegate into a function pointer with burst, invokable from a Burst Job or from regular C#.
  189. /// </summary>
  190. /// <typeparam name="T">Type of the delegate of the function pointer</typeparam>
  191. /// <param name="delegateMethod">The delegate to compile</param>
  192. /// <returns>A function pointer invokable from a Burst Job or from regular C#</returns>
  193. public static unsafe FunctionPointer<T> CompileFunctionPointer<T>(T delegateMethod) where T : class
  194. {
  195. VerifyDelegateIsNotMulticast<T>(delegateMethod);
  196. VerifyDelegateHasCorrectUnmanagedFunctionPointerAttribute<T>(delegateMethod);
  197. // We have added support for runtime CompileDelegate in 2018.2+
  198. void* function = Compile(delegateMethod, true);
  199. return new FunctionPointer<T>(new IntPtr(function));
  200. }
  201. [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
  202. internal class StaticTypeReinitAttribute : Attribute
  203. {
  204. public readonly Type reinitType;
  205. public StaticTypeReinitAttribute(Type toReinit)
  206. {
  207. reinitType = toReinit;
  208. }
  209. }
  210. private static unsafe void* Compile(object delegateObj, bool isFunctionPointer)
  211. {
  212. if (!(delegateObj is Delegate)) throw new ArgumentException("object instance must be a System.Delegate", nameof(delegateObj));
  213. var delegateMethod = (Delegate)delegateObj;
  214. return Compile(delegateMethod, delegateMethod.Method, isFunctionPointer);
  215. }
  216. private static unsafe void* Compile(object delegateObj, MethodInfo methodInfo, bool isFunctionPointer, object managedFallbackDelegateObj = null)
  217. {
  218. if (delegateObj == null) throw new ArgumentNullException(nameof(delegateObj));
  219. if (delegateObj.GetType().IsGenericType)
  220. {
  221. throw new InvalidOperationException($"The delegate type `{delegateObj.GetType()}` must be a non-generic type");
  222. }
  223. if (!methodInfo.IsStatic)
  224. {
  225. throw new InvalidOperationException($"The method `{methodInfo}` must be static. Instance methods are not supported");
  226. }
  227. if (methodInfo.IsGenericMethod)
  228. {
  229. throw new InvalidOperationException($"The method `{methodInfo}` must be a non-generic method");
  230. }
  231. void* function;
  232. #if BURST_INTERNAL
  233. // Internally in Burst tests, we callback the C# method instead
  234. function = (void*)InternalCompiler(delegateObj);
  235. #else
  236. var isILPostProcessing = managedFallbackDelegateObj != null;
  237. if (!isILPostProcessing)
  238. {
  239. managedFallbackDelegateObj = delegateObj;
  240. }
  241. #if ENABLE_IL2CPP
  242. if (isFunctionPointer && !isILPostProcessing &&
  243. methodInfo.GetCustomAttributes().All(s => s.GetType().Name != "MonoPInvokeCallbackAttribute"))
  244. {
  245. UnityEngine.Debug.Log($"The method `{methodInfo}` must have `MonoPInvokeCallback` attribute to be compatible with IL2CPP!");
  246. }
  247. #endif
  248. var delegateMethod = delegateObj as Delegate;
  249. var managedFallbackDelegateMethod = managedFallbackDelegateObj as Delegate;
  250. #if UNITY_EDITOR
  251. string defaultOptions;
  252. // In case Burst is disabled entirely from the command line
  253. if (BurstCompilerOptions.ForceDisableBurstCompilation)
  254. {
  255. GCHandle.Alloc(managedFallbackDelegateMethod);
  256. function = (void*)Marshal.GetFunctionPointerForDelegate(managedFallbackDelegateMethod);
  257. return function;
  258. }
  259. if (isFunctionPointer)
  260. {
  261. defaultOptions = "--" + BurstCompilerOptions.OptionJitIsForFunctionPointer + "\n";
  262. // Make sure that the delegate will never be collected
  263. GCHandle.Alloc(managedFallbackDelegateMethod);
  264. var managedFunctionPointer = Marshal.GetFunctionPointerForDelegate(managedFallbackDelegateMethod);
  265. defaultOptions += "--" + BurstCompilerOptions.OptionJitManagedFunctionPointer + "0x" + managedFunctionPointer.ToInt64().ToString("X16");
  266. }
  267. else
  268. {
  269. defaultOptions = "--" + BurstCompilerOptions.OptionJitEnableSynchronousCompilation;
  270. }
  271. string extraOptions;
  272. // The attribute is directly on the method, so we recover the underlying method here
  273. if (Options.TryGetOptions(methodInfo, true, out extraOptions, isForILPostProcessing: isILPostProcessing))
  274. {
  275. if (!string.IsNullOrWhiteSpace(extraOptions))
  276. {
  277. defaultOptions += "\n" + extraOptions;
  278. }
  279. var delegateMethodId = Unity.Burst.LowLevel.BurstCompilerService.CompileAsyncDelegateMethod(delegateObj, defaultOptions);
  280. function = Unity.Burst.LowLevel.BurstCompilerService.GetAsyncCompiledAsyncDelegateMethod(delegateMethodId);
  281. }
  282. #else
  283. // The attribute is directly on the method, so we recover the underlying method here
  284. if (BurstCompilerOptions.HasBurstCompileAttribute(methodInfo))
  285. {
  286. if (Options.EnableBurstCompilation && BurstCompilerHelper.IsBurstGenerated)
  287. {
  288. var delegateMethodId = Unity.Burst.LowLevel.BurstCompilerService.CompileAsyncDelegateMethod(delegateObj, string.Empty);
  289. function = Unity.Burst.LowLevel.BurstCompilerService.GetAsyncCompiledAsyncDelegateMethod(delegateMethodId);
  290. }
  291. else
  292. {
  293. // If this is for direct-call, and we're in a player, with Burst disabled, then we should return null,
  294. // since this managed fallback will never be used.
  295. if (isILPostProcessing)
  296. {
  297. return null;
  298. }
  299. // Make sure that the delegate will never be collected
  300. GCHandle.Alloc(managedFallbackDelegateMethod);
  301. // If we are in a standalone player, and burst is disabled and we are actually
  302. // trying to load a function pointer, in that case we need to support it
  303. // so we are then going to use the managed function directly
  304. // NOTE: When running under IL2CPP, this could lead to a `System.NotSupportedException : To marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition.`
  305. // so in that case, the method needs to have `MonoPInvokeCallback`
  306. // but that's a requirement for IL2CPP, not an issue with burst
  307. function = (void*)Marshal.GetFunctionPointerForDelegate(managedFallbackDelegateMethod);
  308. }
  309. }
  310. #endif
  311. else
  312. {
  313. throw new InvalidOperationException($"Burst cannot compile the function pointer `{methodInfo}` because the `[BurstCompile]` attribute is missing");
  314. }
  315. #endif
  316. // Should not happen but in that case, we are still trying to generated an error
  317. // It can be null if we are trying to compile a function in a standalone player
  318. // and the function was not compiled. In that case, we need to output an error
  319. if (function == null)
  320. {
  321. throw new InvalidOperationException($"Burst failed to compile the function pointer `{methodInfo}`");
  322. }
  323. // When burst compilation is disabled, we are still returning a valid stub function pointer (the a pointer to the managed function)
  324. // so that CompileFunctionPointer actually returns a delegate in all cases
  325. return function;
  326. }
  327. /// <summary>
  328. /// Lets the compiler service know we are shutting down, called by the event on OnDomainUnload, if EditorApplication.quitting was called
  329. /// </summary>
  330. internal static void Shutdown()
  331. {
  332. #if UNITY_EDITOR
  333. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandShutdown);
  334. #endif
  335. }
  336. #if UNITY_EDITOR
  337. internal static void DomainReload()
  338. {
  339. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandDomainReload);
  340. }
  341. internal static string VersionNotify(string version)
  342. {
  343. return SendCommandToCompiler(BurstCompilerOptions.CompilerCommandVersionNotification, version);
  344. }
  345. internal static void UpdateAssemblerFolders(List<string> folders)
  346. {
  347. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandUpdateAssemblyFolders, $"{string.Join(";", folders)}");
  348. }
  349. #endif
  350. /// <summary>
  351. /// Cancel any compilation being processed by the JIT Compiler in the background.
  352. /// </summary>
  353. internal static void Cancel()
  354. {
  355. #if UNITY_EDITOR
  356. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandCancel);
  357. #endif
  358. }
  359. internal static void Enable()
  360. {
  361. #if UNITY_EDITOR
  362. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandEnableCompiler);
  363. #endif
  364. }
  365. internal static void Disable()
  366. {
  367. #if UNITY_EDITOR
  368. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandDisableCompiler);
  369. #endif
  370. }
  371. internal static bool IsHostEditorArm()
  372. {
  373. #if UNITY_EDITOR
  374. return SendCommandToCompiler(BurstCompilerOptions.CompilerCommandIsArmTestEnv)=="true";
  375. #else
  376. return false;
  377. #endif
  378. }
  379. internal static void TriggerUnsafeStaticMethodRecompilation()
  380. {
  381. foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
  382. {
  383. var reinitAttributes = asm.GetCustomAttributes().Where(
  384. x => x.GetType().FullName == "Unity.Burst.BurstCompiler+StaticTypeReinitAttribute"
  385. );
  386. foreach (var attribute in reinitAttributes)
  387. {
  388. var ourAttribute = attribute as StaticTypeReinitAttribute;
  389. var type = ourAttribute.reinitType;
  390. var method = type.GetMethod("Constructor",BindingFlags.Static|BindingFlags.Public);
  391. method.Invoke(null, new object[] { });
  392. }
  393. }
  394. }
  395. internal static void TriggerRecompilation()
  396. {
  397. #if UNITY_EDITOR
  398. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandTriggerRecompilation, Options.GetOptions(true));
  399. #endif
  400. }
  401. internal static void UnloadAdditionalLibraries()
  402. {
  403. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandUnloadBurstNatives);
  404. }
  405. internal static bool IsApiAvailable(string apiName)
  406. {
  407. return SendCommandToCompiler(BurstCompilerOptions.CompilerCommandIsNativeApiAvailable, apiName) == "True";
  408. }
  409. internal static void EagerCompileMethods(List<EagerCompilationRequest> requests)
  410. {
  411. #if UNITY_EDITOR
  412. // The order of these arguments MUST match the corresponding code in JitCompilerService.EagerCompileMethods.
  413. const string parameterSeparator = "***";
  414. const string requestParametersSeparator = "+++";
  415. const string methodSeparator = "```";
  416. var builder = new StringBuilder();
  417. builder.Append(EagerCompileCompileCallbackFunctionPointer);
  418. builder.Append(parameterSeparator);
  419. builder.Append(EagerCompileLogCallbackFunctionPointer);
  420. builder.Append(parameterSeparator);
  421. foreach (var request in requests)
  422. {
  423. builder.Append(request.EncodedMethod);
  424. builder.Append(requestParametersSeparator);
  425. builder.Append(request.Options);
  426. builder.Append(methodSeparator);
  427. }
  428. builder.Append(parameterSeparator);
  429. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandEagerCompileMethods, builder.ToString());
  430. #endif
  431. }
  432. #if UNITY_EDITOR
  433. private unsafe delegate void CompileCallbackDelegate(void* userdata, NativeDumpFlags dumpFlags, void* dataPtr);
  434. private static unsafe void EagerCompileCompileCallback(void* userData, NativeDumpFlags dumpFlags, void* dataPtr) { }
  435. private static readonly string EagerCompileCompileCallbackFunctionPointer;
  436. private unsafe delegate void LogCallbackDelegate(void* userData, int logType, byte* message, byte* fileName, int lineNumber);
  437. private static unsafe void EagerCompileLogCallback(void* userData, int logType, byte* message, byte* fileName, int lineNumber)
  438. {
  439. if (EagerCompilationLoggingEnabled)
  440. {
  441. BurstRuntime.Log(message, logType, fileName, lineNumber);
  442. }
  443. }
  444. internal static bool EagerCompilationLoggingEnabled = false;
  445. private static readonly string EagerCompileLogCallbackFunctionPointer;
  446. #endif
  447. internal static void WaitUntilCompilationFinished()
  448. {
  449. #if UNITY_EDITOR
  450. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandWaitUntilCompilationFinished);
  451. #endif
  452. }
  453. internal static void ClearEagerCompilationQueues()
  454. {
  455. #if UNITY_EDITOR
  456. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandClearEagerCompilationQueues);
  457. #endif
  458. }
  459. internal static void CancelEagerCompilation()
  460. {
  461. #if UNITY_EDITOR
  462. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandCancelEagerCompilation);
  463. #endif
  464. }
  465. internal static void SetProgressCallback()
  466. {
  467. #if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
  468. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandSetProgressCallback, ProgressCallbackFunctionPointer);
  469. #endif
  470. }
  471. #if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
  472. private delegate void ProgressCallbackDelegate(int current, int total);
  473. private static readonly string ProgressCallbackFunctionPointer;
  474. private static void ProgressCallback(int current, int total)
  475. {
  476. OnProgress?.Invoke(current, total);
  477. }
  478. internal static event Action<int, int> OnProgress;
  479. #endif
  480. internal static void RequestClearJitCache()
  481. {
  482. #if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
  483. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandRequestClearJitCache);
  484. #endif
  485. }
  486. internal static void SetProfilerCallbacks()
  487. {
  488. #if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
  489. SendCommandToCompiler(
  490. BurstCompilerOptions.CompilerCommandSetProfileCallbacks,
  491. ProfileBeginCallbackFunctionPointer + ";" + ProfileEndCallbackFunctionPointer);
  492. #endif
  493. }
  494. #if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
  495. internal delegate void ProfileBeginCallbackDelegate(string markerName, string metadataName, string metadataValue);
  496. internal delegate void ProfileEndCallbackDelegate(string markerName);
  497. private static readonly string ProfileBeginCallbackFunctionPointer;
  498. private static readonly string ProfileEndCallbackFunctionPointer;
  499. private static void ProfileBeginCallback(string markerName, string metadataName, string metadataValue) => OnProfileBegin?.Invoke(markerName, metadataName, metadataValue);
  500. private static void ProfileEndCallback(string markerName) => OnProfileEnd?.Invoke(markerName);
  501. internal static event ProfileBeginCallbackDelegate OnProfileBegin;
  502. internal static event ProfileEndCallbackDelegate OnProfileEnd;
  503. #endif
  504. internal static void Reset()
  505. {
  506. #if UNITY_EDITOR
  507. SendCommandToCompiler(BurstCompilerOptions.CompilerCommandReset);
  508. #endif
  509. }
  510. private static string SendCommandToCompiler(string commandName, string commandArgs = null)
  511. {
  512. if (commandName == null) throw new ArgumentNullException(nameof(commandName));
  513. var compilerOptions = commandName;
  514. if (commandArgs != null)
  515. {
  516. compilerOptions += " " + commandArgs;
  517. }
  518. var results = Unity.Burst.LowLevel.BurstCompilerService.GetDisassembly(DummyMethodInfo, compilerOptions);
  519. if (!string.IsNullOrEmpty(results))
  520. return results.TrimStart('\n');
  521. return "";
  522. }
  523. private static readonly MethodInfo DummyMethodInfo = typeof(BurstCompiler).GetMethod(nameof(DummyMethod), BindingFlags.Static | BindingFlags.NonPublic);
  524. /// <summary>
  525. /// Dummy empty method for being able to send a command to the compiler
  526. /// </summary>
  527. private static void DummyMethod() { }
  528. #if !UNITY_EDITOR && !BURST_INTERNAL
  529. /// <summary>
  530. /// Internal class to detect at standalone player time if AOT settings were enabling burst.
  531. /// </summary>
  532. [BurstCompile]
  533. internal static class BurstCompilerHelper
  534. {
  535. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  536. private delegate bool IsBurstEnabledDelegate();
  537. private static readonly IsBurstEnabledDelegate IsBurstEnabledImpl = new IsBurstEnabledDelegate(IsBurstEnabled);
  538. [BurstCompile]
  539. [AOT.MonoPInvokeCallback(typeof(IsBurstEnabledDelegate))]
  540. private static bool IsBurstEnabled()
  541. {
  542. bool result = true;
  543. DiscardedMethod(ref result);
  544. return result;
  545. }
  546. [BurstDiscard]
  547. private static void DiscardedMethod(ref bool value)
  548. {
  549. value = false;
  550. }
  551. private static unsafe bool IsCompiledByBurst(Delegate del)
  552. {
  553. var delegateMethodId = Unity.Burst.LowLevel.BurstCompilerService.CompileAsyncDelegateMethod(del, string.Empty);
  554. // We don't try to run the method, having a pointer is already enough to tell us that burst was active for AOT settings
  555. return Unity.Burst.LowLevel.BurstCompilerService.GetAsyncCompiledAsyncDelegateMethod(delegateMethodId) != (void*)0;
  556. }
  557. /// <summary>
  558. /// Gets a boolean indicating whether burst was enabled for standalone player, used only at runtime.
  559. /// </summary>
  560. public static readonly bool IsBurstGenerated = IsCompiledByBurst(IsBurstEnabledImpl);
  561. }
  562. #endif // !UNITY_EDITOR && !BURST_INTERNAL
  563. /// <summary>
  564. /// Fake delegate class to make BurstCompilerService.CompileAsyncDelegateMethod happy
  565. /// so that it can access the underlying static method via the property get_Method.
  566. /// So this class is not a delegate.
  567. /// </summary>
  568. private class FakeDelegate
  569. {
  570. public FakeDelegate(MethodInfo method)
  571. {
  572. Method = method;
  573. }
  574. [Preserve]
  575. public MethodInfo Method { get; }
  576. }
  577. #else // UNITY_DOTSPLAYER || NET_DOTS
  578. /// <summary>
  579. /// Compile the following delegate into a function pointer with burst, invokable from a Burst Job or from regular C#.
  580. /// </summary>
  581. /// <typeparam name="T">Type of the delegate of the function pointer</typeparam>
  582. /// <param name="delegateMethod">The delegate to compile</param>
  583. /// <returns>A function pointer invokable from a Burst Job or from regular C#</returns>
  584. public static unsafe FunctionPointer<T> CompileFunctionPointer<T>(T delegateMethod) where T : System.Delegate
  585. {
  586. // Make sure that the delegate will never be collected
  587. GCHandle.Alloc(delegateMethod);
  588. return new FunctionPointer<T>(Marshal.GetFunctionPointerForDelegate(delegateMethod));
  589. }
  590. internal static bool IsApiAvailable(string apiName)
  591. {
  592. return false;
  593. }
  594. #endif
  595. }
  596. }