A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR
2using System;
3using System.Collections.Generic;
4using System.IO;
5using System.Linq;
6using System.Reflection;
7using System.Runtime.CompilerServices;
8using System.Runtime.InteropServices;
9using Unity.Burst.LowLevel;
10using Unity.Profiling;
11using Unity.Profiling.LowLevel;
12using Unity.Profiling.LowLevel.Unsafe;
13using UnityEditor;
14using UnityEditor.Compilation;
15using UnityEditor.Scripting.ScriptCompilation;
16using UnityEngine;
17
18namespace Unity.Burst.Editor
19{
20 /// <summary>
21 /// Main entry point for initializing the burst compiler service for both JIT and AOT
22 /// </summary>
23 [InitializeOnLoad]
24 internal class BurstLoader
25 {
26 private const int BURST_PROTOCOL_VERSION = 1;
27
28 // Cache the delegate to make sure it doesn't get collected.
29 private static readonly BurstCompilerService.ExtractCompilerFlags TryGetOptionsFromMemberDelegate = TryGetOptionsFromMember;
30
31 /// <summary>
32 /// Gets the location to the runtime path of burst.
33 /// </summary>
34 public static string RuntimePath { get; private set; }
35
36 public static BclConfiguration BclConfiguration { get; private set; }
37
38 public static bool IsDebugging { get; private set; }
39
40 public static bool SafeShutdown { get; private set; }
41
42 public static int ProtocolVersion { get; private set; }
43
44 private static void VersionUpdateCheck()
45 {
46 var seek = "com.unity.burst@";
47 var first = RuntimePath.LastIndexOf(seek);
48 var last = RuntimePath.LastIndexOf(".Runtime");
49 string version;
50 if (first == -1 || last == -1 || last <= first)
51 {
52 version = "Unknown";
53 }
54 else
55 {
56 first += seek.Length;
57 last -= 1;
58 version = RuntimePath.Substring(first, last - first);
59 }
60
61 var result = BurstCompiler.VersionNotify(version);
62 // result will be empty if we are shutting down, and thus we shouldn't popup a dialog
63 if (!String.IsNullOrEmpty(result) && result != version)
64 {
65 if (IsDebugging)
66 {
67 UnityEngine.Debug.LogWarning($"[com.unity.burst] - '{result}' != '{version}'");
68 }
69 OnVersionChangeDetected();
70 }
71 }
72
73 private static bool UnityBurstRuntimePathOverwritten(out string path)
74 {
75 path = Environment.GetEnvironmentVariable("UNITY_BURST_RUNTIME_PATH");
76 return Directory.Exists(path);
77 }
78
79 private static void OnVersionChangeDetected()
80 {
81 // Write marker file to tell Burst to delete the cache at next startup.
82 try
83 {
84 File.Create(Path.Combine(BurstCompilerOptions.DefaultCacheFolder, BurstCompilerOptions.DeleteCacheMarkerFileName)).Dispose();
85 }
86 catch (IOException)
87 {
88 // In the unlikely scenario that two processes are creating this marker file at the same time,
89 // and one of them fails, do nothing because the other one has hopefully succeeded.
90 }
91
92 // Skip checking if we are using an explicit runtime path.
93 if (!UnityBurstRuntimePathOverwritten(out var _))
94 {
95 EditorUtility.DisplayDialog("Burst Package Update Detected", "The version of Burst used by your project has changed. Please restart the Editor to continue.", "OK");
96 BurstCompiler.Shutdown();
97 }
98 }
99
100 private static CompilationTaskReason _currentBuildKind;
101
102 static BurstLoader()
103 {
104 if (BurstCompilerOptions.ForceDisableBurstCompilation)
105 {
106 if (!BurstCompilerOptions.IsSecondaryUnityProcess)
107 {
108 UnityEngine.Debug.LogWarning("[com.unity.burst] Burst is disabled entirely from the command line or environment variable");
109 }
110 return;
111 }
112
113 // This can be setup to get more diagnostics
114 var debuggingStr = Environment.GetEnvironmentVariable("UNITY_BURST_DEBUG");
115 IsDebugging = debuggingStr != null && int.TryParse(debuggingStr, out var debugLevel) && debugLevel > 0;
116 if (IsDebugging)
117 {
118 UnityEngine.Debug.LogWarning("[com.unity.burst] Extra debugging is turned on.");
119 }
120
121 // Try to load the runtime through an environment variable
122 var isRuntimePathOverwritten = UnityBurstRuntimePathOverwritten(out var path);
123 if (!isRuntimePathOverwritten)
124 {
125 // Otherwise try to load it from the package itself
126#if UNITY_2021_3_OR_NEWER
127 path = FileUtil.GetPhysicalPath("Packages/com.unity.burst/.Runtime");
128#else
129 path = Path.GetFullPath("Packages/com.unity.burst/.Runtime");
130#endif
131 }
132
133 RuntimePath = path;
134
135 BclConfiguration = GetBclConfiguration(path, isRuntimePathOverwritten);
136
137 if (IsDebugging)
138 {
139 UnityEngine.Debug.LogWarning($"[com.unity.burst] Runtime directory set to {RuntimePath}");
140 }
141
142 BurstCompilerService.Initialize(RuntimePath, TryGetOptionsFromMemberDelegate);
143
144 ProtocolVersion = BurstCompiler.RequestSetProtocolVersion(BURST_PROTOCOL_VERSION);
145
146 BurstCompiler.Initialize(GetAssemblyFolders(),BurstAssemblyDisable.GetDisabledAssemblies(BurstAssemblyDisable.DisableType.Editor, ""));
147
148 // It's important that this call comes *after* BurstCompilerService.Initialize,
149 // otherwise any calls from within EnsureSynchronized to BurstCompilerService,
150 // such as BurstCompiler.Disable(), will silently fail.
151 BurstEditorOptions.EnsureSynchronized();
152
153 EditorApplication.quitting += OnEditorApplicationQuitting;
154
155 CompilationPipeline.compilationStarted += OnCompilationStarted;
156 CompilationPipeline.compilationFinished += OnCompilationFinished;
157
158 // We use this internal event because it's the only way to get access to the ScriptAssembly.HasCompileErrors,
159 // which tells us whether C# compilation succeeded or failed for this assembly.
160 EditorCompilationInterface.Instance.assemblyCompilationFinished += OnAssemblyCompilationFinished;
161
162#if UNITY_2022_2_OR_NEWER
163 CompilationPipeline.assemblyCompilationNotRequired += OnAssemblyCompilationNotRequired;
164#endif
165
166 EditorApplication.playModeStateChanged += EditorApplicationOnPlayModeStateChanged;
167 AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;
168
169 SafeShutdown = false;
170 UnityEditor.PackageManager.Events.registeringPackages += PackageRegistrationEvent;
171 SafeShutdown = BurstCompiler.IsApiAvailable("SafeShutdown");
172
173 if (!SafeShutdown)
174 {
175 VersionUpdateCheck();
176 }
177
178 // Notify the compiler about a domain reload
179 if (IsDebugging)
180 {
181 UnityEngine.Debug.Log("Burst - Domain Reload");
182 }
183
184 BurstCompiler.OnProgress += OnProgress;
185
186 BurstCompiler.EagerCompilationLoggingEnabled = true;
187
188 // Make sure BurstRuntime is initialized. This needs to happen before BurstCompiler.DomainReload,
189 // because that can cause calls to BurstRuntime.Log.
190 BurstRuntime.Initialize();
191
192 // Notify the JitCompilerService about a domain reload
193 BurstCompiler.SetDefaultOptions();
194 BurstCompiler.DomainReload();
195
196 BurstCompiler.OnProfileBegin += OnProfileBegin;
197 BurstCompiler.OnProfileEnd += OnProfileEnd;
198 BurstCompiler.SetProfilerCallbacks();
199
200 BurstCompiler.InitialiseDebuggerHooks();
201 }
202
203 private static bool _isQuitting;
204 private static void OnEditorApplicationQuitting()
205 {
206 _isQuitting = true;
207 }
208
209 public static Action OnBurstShutdown;
210
211 private static void PackageRegistrationEvent(UnityEditor.PackageManager.PackageRegistrationEventArgs obj)
212 {
213 bool requireCleanup = false;
214 if (SafeShutdown)
215 {
216 foreach (var changed in obj.changedFrom)
217 {
218 if (changed.name.Contains("com.unity.burst"))
219 {
220 requireCleanup = true;
221 break;
222 }
223 }
224 }
225
226 foreach (var removed in obj.removed)
227 {
228 if (removed.name.Contains("com.unity.burst"))
229 {
230 requireCleanup = true;
231 }
232 }
233
234 if (requireCleanup)
235 {
236 OnBurstShutdown?.Invoke();
237 if (!SafeShutdown)
238 {
239 EditorUtility.DisplayDialog("Burst Package Has Been Removed", "Please restart the Editor to continue.", "OK");
240 }
241 BurstCompiler.Shutdown();
242 }
243 }
244
245 private static BclConfiguration GetBclConfiguration(string runtimePath, bool isRuntimePathOverwritten)
246 {
247 string bclFolderPath;
248 if (isRuntimePathOverwritten)
249 {
250 return new BclConfiguration
251 {
252 FolderPath = runtimePath,
253 ExecutablePath = Path.Combine(runtimePath, "bcl.exe"),
254 IsExecutableNative = false,
255 };
256 }
257 else
258 {
259 bclFolderPath = Path.Combine(runtimePath, "bcl", GetBclPlatformFolderName());
260 if (Directory.Exists(bclFolderPath))
261 {
262 var bclFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
263 ? "bcl.exe"
264 : "bcl";
265
266 return new BclConfiguration
267 {
268 FolderPath = bclFolderPath,
269 ExecutablePath = Path.Combine(bclFolderPath, bclFileName),
270 IsExecutableNative = true,
271 };
272 }
273
274 return new BclConfiguration
275 {
276 FolderPath = runtimePath,
277 ExecutablePath = Path.Combine(runtimePath, "bcl.exe"),
278 IsExecutableNative = false,
279 };
280 }
281 }
282
283 private static string GetBclPlatformFolderName()
284 {
285 var hostPlatform = Application.platform;
286 var hostArchitecture = RuntimeInformation.OSArchitecture;
287
288 switch (hostPlatform)
289 {
290 case RuntimePlatform.WindowsEditor:
291 return "win-x64";
292
293 case RuntimePlatform.OSXEditor when hostArchitecture == Architecture.X64:
294 return "osx-x64";
295
296 case RuntimePlatform.OSXEditor when hostArchitecture == Architecture.Arm64:
297 return "osx-arm64";
298
299 case RuntimePlatform.LinuxEditor:
300 return "linux-x64";
301
302 default:
303 throw new InvalidOperationException($"Current OS platform {hostPlatform} and architecture {hostArchitecture} combination is not supported");
304 }
305 }
306
307 // Don't initialize to 0 because that could be a valid progress ID.
308 private static int BurstProgressId = -1;
309
310 // If this enum changes, update the benchmarks tool accordingly as we rely on integer value related to this enum
311 internal enum BurstEagerCompilationStatus
312 {
313 NotScheduled,
314 Scheduled,
315 Completed
316 }
317
318 // For the time being, this field is only read through reflection
319 internal static BurstEagerCompilationStatus EagerCompilationStatus;
320
321 private static void OnProgress(int current, int total)
322 {
323 if (current == total)
324 {
325 EagerCompilationStatus = BurstEagerCompilationStatus.Completed;
326 }
327
328 // OnProgress is called from a background thread,
329 // but we need to update the progress UI on the main thread.
330 EditorApplication.CallDelayed(() =>
331 {
332 if (current == total)
333 {
334 // We've finished - remove progress bar.
335 if (Progress.Exists(BurstProgressId))
336 {
337 Progress.Remove(BurstProgressId);
338 BurstProgressId = -1;
339 }
340 }
341 else
342 {
343 // Do we need to create the progress bar?
344 if (!Progress.Exists(BurstProgressId))
345 {
346 BurstProgressId = Progress.Start(
347 "Burst",
348 "Compiling...",
349 Progress.Options.Unmanaged);
350 }
351
352 Progress.Report(
353 BurstProgressId,
354 current / (float)total,
355 $"Compiled {current} / {total} libraries");
356 }
357 });
358 }
359
360 [ThreadStatic]
361 private static Dictionary<string, IntPtr> ProfilerMarkers;
362
363 private static unsafe void OnProfileBegin(string markerName, string metadataName, string metadataValue)
364 {
365 if (ProfilerMarkers == null)
366 {
367 // Initialize thread-static dictionary.
368 ProfilerMarkers = new Dictionary<string, IntPtr>();
369 }
370
371 if (!ProfilerMarkers.TryGetValue(markerName, out var markerPtr))
372 {
373 ProfilerMarkers.Add(markerName, markerPtr = ProfilerUnsafeUtility.CreateMarker(
374 markerName,
375 ProfilerUnsafeUtility.CategoryScripts,
376 MarkerFlags.Script,
377 metadataName != null ? 1 : 0));
378
379 // metadataName is assumed to be consistent for a given markerName.
380 if (metadataName != null)
381 {
382 ProfilerUnsafeUtility.SetMarkerMetadata(
383 markerPtr,
384 0,
385 metadataName,
386 (byte)ProfilerMarkerDataType.String16,
387 (byte)ProfilerMarkerDataUnit.Undefined);
388 }
389 }
390
391 if (metadataName != null && metadataValue != null)
392 {
393 fixed (char* methodNamePtr = metadataValue)
394 {
395 var metadata = new ProfilerMarkerData
396 {
397 Type = (byte)ProfilerMarkerDataType.String16,
398 Size = ((uint)metadataValue.Length + 1) * 2,
399 Ptr = methodNamePtr
400 };
401 ProfilerUnsafeUtility.BeginSampleWithMetadata(markerPtr, 1, &metadata);
402 }
403 }
404 else
405 {
406 ProfilerUnsafeUtility.BeginSample(markerPtr);
407 }
408 }
409
410 private static void OnProfileEnd(string markerName)
411 {
412 if (ProfilerMarkers == null)
413 {
414 // If we got here it means we had a domain reload between when we called profile begin and
415 // now profile end, and so we need to bail out.
416 return;
417 }
418
419 if (!ProfilerMarkers.TryGetValue(markerName, out var markerPtr))
420 {
421 return;
422 }
423
424 ProfilerUnsafeUtility.EndSample(markerPtr);
425 }
426
427 private static void EditorApplicationOnPlayModeStateChanged(PlayModeStateChange state)
428 {
429 if (IsDebugging)
430 {
431 UnityEngine.Debug.Log($"Burst - Change of Editor State: {state}");
432 }
433
434 switch (state)
435 {
436 case PlayModeStateChange.ExitingPlayMode:
437 // Cleanup any loaded burst natives so users have a clean point to update the libraries.
438 BurstCompiler.UnloadAdditionalLibraries();
439 break;
440 }
441 }
442
443 enum CompilationTaskReason
444 {
445 IsForEditor, // Compilation should proceed as its for an editor build
446 IsForPlayer, // Skip this compilation
447 IsForPreviousScriptingMode, // We are about to enter a domain reload, don't start any new compilations
448 IsForAssemblyBuilder, // Request is coming from an 'AssemblyBuilder' and should be skipped as not supported
449 }
450
451 static CompilationTaskReason CurrentCompilationTaskShouldStart()
452 {
453 try
454 {
455 if (BurstCompiler.WasScriptDebugInfoEnabledAtDomainReload != UnityEditor.Compilation.CompilationPipeline.IsScriptDebugInfoEnabled())
456 {
457 // If the scripting compilation mode has changed since we last had our domain reloaded, then we ignore all requests, and act as if
458 //loading for the first time. This is to avoid having compilations kick off right before a Shutdown triggered by domain reload, that
459 //would cause the a significant stall as we had to wait for those compilations to finish, thus blocking the main thread.
460 return CompilationTaskReason.IsForPreviousScriptingMode;
461 }
462
463 var inst = EditorCompilationInterface.Instance;
464
465#if UNITY_2021_1_OR_NEWER
466 var editorCompilationType = inst.GetType();
467 var activeBeeBuildField = editorCompilationType.GetField("_currentBeeScriptCompilationState", BindingFlags.Instance | BindingFlags.NonPublic);
468 if (activeBeeBuildField == null)
469 {
470 activeBeeBuildField = editorCompilationType.GetField("activeBeeBuild", BindingFlags.Instance | BindingFlags.NonPublic);
471 }
472 var activeBeeBuild = activeBeeBuildField.GetValue(inst);
473
474 // If a user is doing an `AssemblyBuilder` compilation, we do not support that in Burst.
475 // This seems to manifest as a null `activeBeeBuild`, so we bail here if that happens.
476 if (activeBeeBuild == null)
477 {
478 return CompilationTaskReason.IsForAssemblyBuilder;
479 }
480
481 var settings = activeBeeBuild.GetType().GetProperty("settings", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(activeBeeBuild);
482 var opt = (EditorScriptCompilationOptions)settings.GetType().GetProperty("CompilationOptions").GetValue(settings);
483#else
484 var task = inst.GetType()
485 .GetField("compilationTask", BindingFlags.Instance | BindingFlags.NonPublic)
486 .GetValue(inst);
487
488 // If a user is doing an `AssemblyBuilder` compilation, we do not support that in Burst.
489 // This seems to manifest as a null `task`, so we bail here if that happens.
490 if (task == null)
491 {
492 return CompilationTaskReason.IsForAssemblyBuilder;
493 }
494
495 var opt = (EditorScriptCompilationOptions)task.GetType()
496 .GetField("options", BindingFlags.Instance | BindingFlags.NonPublic)
497 .GetValue(task);
498#endif
499
500#if UNITY_2022_2_OR_NEWER
501 if ((opt & EditorScriptCompilationOptions.BuildingSkipCompile) != 0)
502 {
503 return CompilationTaskReason.IsForPlayer;
504 }
505#endif
506
507 if ((opt & EditorScriptCompilationOptions.BuildingForEditor) != 0)
508 {
509 return CompilationTaskReason.IsForEditor;
510 }
511
512 return CompilationTaskReason.IsForPlayer;
513 }
514 catch (Exception ex)
515 {
516 UnityEngine.Debug.LogWarning("Burst - Unknown private compilation pipeline API\nAssuming editor build\n" + ex.ToString());
517
518 return CompilationTaskReason.IsForEditor;
519 }
520 }
521
522 private static void OnCompilationStarted(object value)
523 {
524 _currentBuildKind = CurrentCompilationTaskShouldStart();
525 if (_currentBuildKind != CompilationTaskReason.IsForEditor)
526 {
527 if (IsDebugging)
528 {
529 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - not handling '{value}' because '{_currentBuildKind}'");
530 }
531 return;
532 }
533
534 if (IsDebugging)
535 {
536 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - compilation started for '{value}'");
537 }
538
539 BurstCompiler.NotifyCompilationStarted(GetAssemblyFolders(),
540 BurstAssemblyDisable.GetDisabledAssemblies(BurstAssemblyDisable.DisableType.Editor,"") );
541 }
542
543 private static string[] GetAssemblyFolders()
544 {
545 var assemblyFolders = new HashSet<string>();
546
547 // First, we get the path to Mono system libraries. This will be something like
548 // <EditorPath>/Data/MonoBleedingEdge/lib/mono/unityjit-win32
549 //
550 // You might think we could use MonoLibraryHelpers.GetSystemReferenceDirectories
551 // here, but we can't, because that returns the _reference assembly_ directories,
552 // not the actual implementation assembly directory.
553 var systemLibraryDirectory = Path.GetDirectoryName(typeof(object).Assembly.Location);
554 assemblyFolders.Add(systemLibraryDirectory);
555
556 // Also add the Facades directory, since that contains netstandard. Without this,
557 // we'll potentially resolve the "wrong" netstandard from a dotnet compiler host.
558 assemblyFolders.Add(Path.Combine(systemLibraryDirectory, "Facades"));
559
560 // Now add the default assembly search paths.
561 // This will include
562 // - Unity dlls in <EditorPath>/Data/Managed and <EditorPath>/Data/Managed/UnityEngine
563 // - Platform support dlls e.g. <EditorPath>/Data/PlaybackEngines/WindowsStandaloneSupport
564 // - Package paths. These are interesting because they are "virtual" paths, of the form
565 // Packages/<MyPackageName>. They need to be resolved to physical paths.
566 // - Library/ScriptAssemblies. This needs to be resolved to the full path.
567 var defaultAssemblySearchPaths = AssemblyHelper.GetDefaultAssemblySearchPaths();
568#if UNITY_2021_3_OR_NEWER
569 foreach (var searchPath in defaultAssemblySearchPaths)
570 {
571 var resolvedPath = FileUtil.PathToAbsolutePath(searchPath);
572 if (!string.IsNullOrEmpty(resolvedPath))
573 {
574 assemblyFolders.Add(resolvedPath);
575 }
576 }
577#else
578 var packagesLookup = GetPackagesLookup();
579 foreach (var searchPath in defaultAssemblySearchPaths)
580 {
581 if (TryResolvePath(searchPath, packagesLookup, out var resolvedPath))
582 {
583 assemblyFolders.Add(resolvedPath);
584 }
585 }
586#endif
587
588 if (IsDebugging)
589 {
590 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - AssemblyFolders : \n{string.Join("\n", assemblyFolders)}");
591 }
592
593 return assemblyFolders.ToArray();
594 }
595
596#if !UNITY_2021_3_OR_NEWER
597 private static Dictionary<string, string> GetPackagesLookup()
598 {
599 var packages = new Dictionary<string, string>();
600
601 // Fetch list of packages
602#if UNITY_2021_1_OR_NEWER
603 var allPackages = UnityEditor.PackageManager.PackageInfo.GetAllRegisteredPackages();
604#else
605 var allPackages = UnityEditor.PackageManager.PackageInfo.GetAll();
606#endif
607 foreach (var p in allPackages)
608 {
609 packages.Add(p.name, p.resolvedPath);
610 }
611
612 return packages;
613 }
614
615 private const string PackagesPath = "Packages/";
616 private static readonly int PackagesPathLength = PackagesPath.Length;
617
618 private static bool TryResolvePath(string path, Dictionary<string, string> packagesLookup, out string resolvedPath)
619 {
620 if (string.IsNullOrEmpty(path))
621 {
622 resolvedPath = null;
623 return false;
624 }
625 else if (path.StartsWith("Packages/", StringComparison.InvariantCulture))
626 {
627 var secondSlashIndex = path.IndexOf('/', PackagesPathLength);
628 var packageName = secondSlashIndex > -1
629 ? path.Substring(PackagesPathLength, secondSlashIndex - PackagesPathLength)
630 : path.Substring(PackagesPathLength);
631
632 if (packagesLookup.TryGetValue(packageName, out var resolvedPathTemp))
633 {
634 path = secondSlashIndex > -1
635 ? Path.Combine(resolvedPathTemp, path.Substring(secondSlashIndex + 1))
636 : resolvedPathTemp;
637 }
638 else
639 {
640 if (IsDebugging)
641 {
642 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - unknown package path '{path}'");
643 }
644 resolvedPath = null;
645 return false;
646 }
647 }
648
649 resolvedPath = Path.GetFullPath(path);
650 return true;
651 }
652#endif
653
654 private static void OnCompilationFinished(object value)
655 {
656 if (_currentBuildKind!=CompilationTaskReason.IsForEditor)
657 {
658 if (IsDebugging)
659 {
660 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - ignoring finished compilation '{value}' because it's '{_currentBuildKind}'");
661 }
662
663 _currentBuildKind = CompilationTaskReason.IsForEditor;
664 return;
665 }
666
667 if (IsDebugging)
668 {
669 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - compilation finished for '{value}'");
670 }
671
672 BurstCompiler.NotifyCompilationFinished();
673 }
674
675#if UNITY_2021_1_OR_NEWER
676 private static void OnAssemblyCompilationFinished(ScriptAssembly assembly, CompilerMessage[] messages)
677#else
678 private static void OnAssemblyCompilationFinished(ScriptAssembly assembly, CompilerMessage[] messages, EditorScriptCompilationOptions options)
679#endif
680 {
681 if (_currentBuildKind!=CompilationTaskReason.IsForEditor)
682 {
683 if (IsDebugging)
684 {
685 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - ignoring '{assembly.Filename}' because it's '{_currentBuildKind}'");
686 }
687
688 return;
689 }
690
691 if (IsDebugging)
692 {
693 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - Assembly compilation finished for '{assembly.Filename}'");
694 }
695
696 if (assembly.HasCompileErrors)
697 {
698 if (IsDebugging)
699 {
700 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - ignoring '{assembly.Filename}' because it failed C# compilation");
701 }
702
703 return;
704 }
705
706 BurstCompiler.NotifyAssemblyCompilationFinished(Path.GetFileNameWithoutExtension(assembly.Filename), assembly.Defines);
707 }
708
709 private static void OnAssemblyCompilationNotRequired(string arg1)
710 {
711 if (_currentBuildKind!=CompilationTaskReason.IsForEditor)
712 {
713 if (IsDebugging)
714 {
715 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - ignoring '{arg1}' because it's '{_currentBuildKind}'");
716 }
717
718 return;
719 }
720
721 if (IsDebugging)
722 {
723 UnityEngine.Debug.Log($"{DateTime.UtcNow} Burst - Assembly compilation not required for '{arg1}'");
724 }
725
726 BurstCompiler.NotifyAssemblyCompilationNotRequired(Path.GetFileNameWithoutExtension(arg1));
727 }
728
729 private static bool TryGetOptionsFromMember(MemberInfo member, out string flagsOut)
730 {
731 return BurstCompiler.Options.TryGetOptions(member, out flagsOut);
732 }
733
734 private static void OnDomainUnload(object sender, EventArgs e)
735 {
736 if (IsDebugging)
737 {
738 UnityEngine.Debug.Log($"Burst - OnDomainUnload");
739 }
740
741 BurstCompiler.Cancel();
742
743 // This check here is to execute shutdown after all OnDisable's. EditorApplication.quitting event is called before OnDisable's, so we need to shutdown in here.
744 if (_isQuitting)
745 {
746 BurstCompiler.Shutdown();
747 }
748
749 // Because of a check in Unity (specifically SCRIPTINGAPI_THREAD_AND_SERIALIZATION_CHECK),
750 // we are not allowed to call thread-unsafe methods (like Progress.Exists) after the
751 // kApplicationTerminating bit has been set. And because the domain is unloaded
752 // (thus triggering AppDomain.DomainUnload) *after* that bit is set, we can't call Progress.Exists
753 // during shutdown. So we check _isQuitting here. When quitting, it's fine for the progress item
754 // not to be removed since it's all being torn down anyway.
755 if (!_isQuitting && Progress.Exists(BurstProgressId))
756 {
757 Progress.Remove(BurstProgressId);
758 BurstProgressId = -1;
759 }
760 }
761 }
762
763 internal class BclConfiguration
764 {
765 public string FolderPath { get; set; }
766 public string ExecutablePath { get; set; }
767 public bool IsExecutableNative { get; set; }
768 }
769}
770#endif