diff options
| author | Emmanuel Hansen <emmausssss@gmail.com> | 2024-08-31 14:39:26 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-31 11:39:26 -0300 |
| commit | 2c5c0392f9ff80a3907bbf376a13f797ebbc12cc (patch) | |
| tree | 66eac1cb8ec09aae5196520cad19ab8ee6aba241 /src/Ryujinx.HLE.Generators | |
| parent | e0acde04bb032fd056904b909b3fd00c1a6fb996 (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.cs | 63 | ||||
| -rw-r--r-- | src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs | 76 | ||||
| -rw-r--r-- | src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj | 19 | ||||
| -rw-r--r-- | src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs | 24 |
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); + } + } + } +} |
