diff --git a/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs b/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs
index 6dd82b004..4a1f90059 100644
--- a/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs
+++ b/src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs
@@ -23,14 +23,28 @@ public void Setup()
}
[Benchmark]
- public EmitResult Compile()
+ public EmitResult CompileSingleThreaded()
{
var syntaxTree = SyntaxTree.Parse(this.Input.Code, Path.GetFullPath(this.Input.Path));
var compilation = Compilation.Create(
syntaxTrees: ImmutableArray.Create(syntaxTree),
metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All
.Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes)))
- .ToImmutableArray());
+ .ToImmutableArray(),
+ useMultithreading: false);
+ return compilation.Emit(peStream: this.peStream);
+ }
+
+ [Benchmark]
+ public EmitResult CompileMultiThreaded()
+ {
+ var syntaxTree = SyntaxTree.Parse(this.Input.Code, Path.GetFullPath(this.Input.Path));
+ var compilation = Compilation.Create(
+ syntaxTrees: ImmutableArray.Create(syntaxTree),
+ metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All
+ .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes)))
+ .ToImmutableArray(),
+ useMultithreading: true);
return compilation.Emit(peStream: this.peStream);
}
}
diff --git a/src/Draco.Compiler/Api/Compilation.cs b/src/Draco.Compiler/Api/Compilation.cs
index de35c071f..9036432af 100644
--- a/src/Draco.Compiler/Api/Compilation.cs
+++ b/src/Draco.Compiler/Api/Compilation.cs
@@ -3,6 +3,7 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
using Draco.Compiler.Api.Diagnostics;
using Draco.Compiler.Api.Semantics;
using Draco.Compiler.Api.Syntax;
@@ -45,13 +46,16 @@ public sealed class Compilation : IBinderProvider
/// The path of the root module.
/// The output path.
/// The output assembly name.
+ /// True, if multithreading should be used.
/// The constructed .
public static Compilation Create(
ImmutableArray syntaxTrees,
ImmutableArray? metadataReferences = null,
string? rootModulePath = null,
string? outputPath = null,
- string? assemblyName = null) => new(
+ string? assemblyName = null,
+ bool useMultithreading = true) => new(
+ useMultithreading: useMultithreading,
syntaxTrees: syntaxTrees,
metadataReferences: metadataReferences,
rootModulePath: rootModulePath,
@@ -67,6 +71,11 @@ public static Compilation Create(
.Concat(this.GlobalDiagnosticBag)
.ToImmutableArray();
+ ///
+ /// True, if threading is utilized by the compilation.
+ ///
+ public bool UseMultithreading { get; }
+
///
/// The trees that are being compiled.
///
@@ -148,6 +157,7 @@ public static Compilation Create(
// Main ctor with all state
private Compilation(
+ bool useMultithreading,
ImmutableArray syntaxTrees,
ImmutableArray? metadataReferences,
string? rootModulePath = null,
@@ -162,6 +172,7 @@ private Compilation(
IntrinsicSymbols? intrinsicSymbols = null,
BinderCache? binderCache = null)
{
+ this.UseMultithreading = useMultithreading;
this.SyntaxTrees = syntaxTrees;
this.MetadataReferences = metadataReferences ?? ImmutableArray.Empty;
this.RootModulePath = Path.TrimEndingDirectorySeparator(rootModulePath ?? string.Empty);
@@ -205,6 +216,7 @@ public Compilation UpdateSyntaxTree(SyntaxTree? oldTree, SyntaxTree? newTree)
}
return new Compilation(
+ useMultithreading: this.UseMultithreading,
syntaxTrees: newSyntaxTrees.ToImmutable(),
metadataReferences: this.MetadataReferences,
rootModulePath: this.RootModulePath,
@@ -306,6 +318,31 @@ public EmitResult Emit(
Diagnostics: ImmutableArray.Empty);
}
+ internal Task RunOnThread(Action action)
+ {
+ if (this.UseMultithreading)
+ {
+ return Task.Run(action);
+ }
+ else
+ {
+ action();
+ return Task.CompletedTask;
+ }
+ }
+
+ internal Task RunOnThread(Func func)
+ {
+ if (this.UseMultithreading)
+ {
+ return Task.Run(func);
+ }
+ else
+ {
+ return Task.FromResult(func());
+ }
+ }
+
internal ModuleSymbol GetModuleForSyntaxTree(SyntaxTree tree)
{
var filePath = SplitPath.FromFilePath(tree.SourceText.Path?.LocalPath ?? string.Empty);
diff --git a/src/Draco.Compiler/Api/Semantics/SemanticModel.cs b/src/Draco.Compiler/Api/Semantics/SemanticModel.cs
index 58ac85c4d..80ca79d70 100644
--- a/src/Draco.Compiler/Api/Semantics/SemanticModel.cs
+++ b/src/Draco.Compiler/Api/Semantics/SemanticModel.cs
@@ -83,13 +83,13 @@ private ImmutableArray GetDiagnostics(SourceSpan? span = null)
case CompilationUnitSyntax:
case FunctionDeclarationSyntax:
{
- tasks.Add(Task.Run(() => containingSymbol?.Bind(this)));
+ tasks.Add(this.compilation.RunOnThread(() => containingSymbol?.Bind(this)));
break;
}
// NOTE: Only globals need binding
case VariableDeclarationSyntax when containingSymbol is SourceModuleSymbol containingModule:
{
- tasks.Add(Task.Run(() =>
+ tasks.Add(this.compilation.RunOnThread(() =>
{
// We need to search for this global
var globalSymbol = containingModule.Members