aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE.Generators
diff options
context:
space:
mode:
authorEmmanuel Hansen <emmausssss@gmail.com>2024-08-31 14:39:26 +0000
committerGitHub <noreply@github.com>2024-08-31 11:39:26 -0300
commit2c5c0392f9ff80a3907bbf376a13f797ebbc12cc (patch)
tree66eac1cb8ec09aae5196520cad19ab8ee6aba241 /src/Ryujinx.HLE.Generators
parente0acde04bb032fd056904b909b3fd00c1a6fb996 (diff)
Make HLE project AOT friendly (#7085)
* add hle service generator remove usage of reflection in device state * remove rd.xml generation * make applet manager reflection free * fix typos * fix encoding * fix style report * remove rogue generator reference * remove double assignment
Diffstat (limited to 'src/Ryujinx.HLE.Generators')
-rw-r--r--src/Ryujinx.HLE.Generators/CodeGenerator.cs63
-rw-r--r--src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs76
-rw-r--r--src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj19
-rw-r--r--src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs24
4 files changed, 182 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE.Generators/CodeGenerator.cs b/src/Ryujinx.HLE.Generators/CodeGenerator.cs
new file mode 100644
index 00000000..7e4848ad
--- /dev/null
+++ b/src/Ryujinx.HLE.Generators/CodeGenerator.cs
@@ -0,0 +1,63 @@
+using System.Text;
+
+namespace Ryujinx.HLE.Generators
+{
+ class CodeGenerator
+ {
+ private const int IndentLength = 4;
+
+ private readonly StringBuilder _sb;
+ private int _currentIndentCount;
+
+ public CodeGenerator()
+ {
+ _sb = new StringBuilder();
+ }
+
+ public void EnterScope(string header = null)
+ {
+ if (header != null)
+ {
+ AppendLine(header);
+ }
+
+ AppendLine("{");
+ IncreaseIndentation();
+ }
+
+ public void LeaveScope(string suffix = "")
+ {
+ DecreaseIndentation();
+ AppendLine($"}}{suffix}");
+ }
+
+ public void IncreaseIndentation()
+ {
+ _currentIndentCount++;
+ }
+
+ public void DecreaseIndentation()
+ {
+ if (_currentIndentCount - 1 >= 0)
+ {
+ _currentIndentCount--;
+ }
+ }
+
+ public void AppendLine()
+ {
+ _sb.AppendLine();
+ }
+
+ public void AppendLine(string text)
+ {
+ _sb.Append(' ', IndentLength * _currentIndentCount);
+ _sb.AppendLine(text);
+ }
+
+ public override string ToString()
+ {
+ return _sb.ToString();
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
new file mode 100644
index 00000000..19fdbe19
--- /dev/null
+++ b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
@@ -0,0 +1,76 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Linq;
+
+namespace Ryujinx.HLE.Generators
+{
+ [Generator]
+ public class IpcServiceGenerator : ISourceGenerator
+ {
+ public void Execute(GeneratorExecutionContext context)
+ {
+ var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver;
+ CodeGenerator generator = new CodeGenerator();
+
+ generator.AppendLine("using System;");
+ generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm");
+ generator.EnterScope($"partial class IUserInterface");
+
+ generator.EnterScope($"public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)");
+ foreach (var className in syntaxReceiver.Types)
+ {
+ if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service"))))
+ continue;
+ var name = GetFullName(className, context).Replace("global::", "");
+ if (!name.StartsWith("Ryujinx.HLE.HOS.Services"))
+ continue;
+ var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax);
+
+ if (!constructors.Any(x => x.ParameterList.Parameters.Count >= 1))
+ continue;
+
+ if (constructors.Where(x => x.ParameterList.Parameters.Count >= 1).FirstOrDefault().ParameterList.Parameters[0].Type.ToString() == "ServiceCtx")
+ {
+ generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))");
+ if (constructors.Any(x => x.ParameterList.Parameters.Count == 2))
+ {
+ var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
+ var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
+ var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
+ var fullName = typeSymbol.ToString();
+ generator.EnterScope("if (parameter != null)");
+ generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);");
+ generator.LeaveScope();
+ }
+
+ if (constructors.Any(x => x.ParameterList.Parameters.Count == 1))
+ {
+ generator.AppendLine($"return new {GetFullName(className, context)}(context);");
+ }
+
+ generator.LeaveScope();
+ }
+ }
+
+ generator.AppendLine("return null;");
+ generator.LeaveScope();
+
+ generator.LeaveScope();
+ generator.LeaveScope();
+ context.AddSource($"IUserInterface.g.cs", generator.ToString());
+ }
+
+ private string GetFullName(ClassDeclarationSyntax syntaxNode, GeneratorExecutionContext context)
+ {
+ var typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
+
+ return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ }
+
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ context.RegisterForSyntaxNotifications(() => new ServiceSyntaxReceiver());
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj b/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
new file mode 100644
index 00000000..eeab9c0e
--- /dev/null
+++ b/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
+ <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
+ <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
+ <IsRoslynComponent>true</IsRoslynComponent>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ </PackageReference>
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs b/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs
new file mode 100644
index 00000000..e4269cb9
--- /dev/null
+++ b/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs
@@ -0,0 +1,24 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.Generators
+{
+ internal class ServiceSyntaxReceiver : ISyntaxReceiver
+ {
+ public HashSet<ClassDeclarationSyntax> Types = new HashSet<ClassDeclarationSyntax>();
+
+ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+ {
+ if (syntaxNode is ClassDeclarationSyntax classDeclaration)
+ {
+ if (classDeclaration.BaseList == null)
+ {
+ return;
+ }
+
+ Types.Add(classDeclaration);
+ }
+ }
+ }
+}