From 10d1cd799d4454aedae9e89c5f2fe2f09ef2de70 Mon Sep 17 00:00:00 2001 From: Friedrich von Never Date: Sun, 19 Nov 2023 15:17:18 +0100 Subject: [PATCH] (#354) CodeGen: add integration tests --- .../Cesium.CodeGen.Tests.csproj | 1 + .../CodeGenNetInteropTests.cs | 46 ++++++++++++++++--- Cesium.CodeGen.Tests/CodeGenTestBase.cs | 30 ++++++++---- ...rInterop_architecture=Dynamic.verified.txt | 4 +- ...CPtrInterop_architecture=Wide.verified.txt | 4 +- ...rInterop_architecture=Dynamic.verified.txt | 14 ++++-- ...cPtrInterop_architecture=Wide.verified.txt | 14 ++++-- ...rInterop_architecture=Dynamic.verified.txt | 4 +- ...nterInterop_architecture=Wide.verified.txt | 4 +- ...rInterop_architecture=Dynamic.verified.txt | 4 +- ...nterInterop_architecture=Wide.verified.txt | 4 +- ...rInterop_architecture=Dynamic.verified.txt | 4 +- ...dPtrInterop_architecture=Wide.verified.txt | 4 +- Cesium.CodeGen/Contexts/AssemblyContext.cs | 12 ++++- ...cTypeCache.cs => ConversionMethodCache.cs} | 17 +++---- .../Ir/Expressions/TypeCastExpression.cs | 11 +++-- Cesium.CodeGen/Ir/Types/InteropType.cs | 43 +++++++++++++---- Cesium.Compiler/Cesium.Compiler.csproj | 1 + Cesium.Compiler/RuntimeConfig.cs | 13 ++++++ .../CSharpCompilationUtil.cs | 5 +- 20 files changed, 175 insertions(+), 64 deletions(-) rename Cesium.CodeGen/Contexts/Utilities/{GenericTypeCache.cs => ConversionMethodCache.cs} (69%) diff --git a/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj b/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj index a5d0a61c..73cd85c4 100644 --- a/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj +++ b/Cesium.CodeGen.Tests/Cesium.CodeGen.Tests.csproj @@ -24,6 +24,7 @@ + diff --git a/Cesium.CodeGen.Tests/CodeGenNetInteropTests.cs b/Cesium.CodeGen.Tests/CodeGenNetInteropTests.cs index a83f9a39..c78e6aff 100644 --- a/Cesium.CodeGen.Tests/CodeGenNetInteropTests.cs +++ b/Cesium.CodeGen.Tests/CodeGenNetInteropTests.cs @@ -1,9 +1,11 @@ using System.Diagnostics.CodeAnalysis; +using Cesium.Compiler; using Cesium.Test.Framework; using Xunit.Abstractions; namespace Cesium.CodeGen.Tests; +// TODO: Make them run in parallel, as all the integration tests public class CodeGenNetInteropTests : CodeGenTestBase { private readonly ITestOutputHelper _output; @@ -21,8 +23,40 @@ private async Task DoTest( _output, CSharpCompilationUtil.DefaultRuntime, cSharpCode); - var cesiumAssembly = GenerateAssembly(runtime: null, arch: architecture, sources: new[]{cCode}, referencePaths: new[] { cSharpAssemblyPath }); + var (cesiumAssembly, assemblyContents) = GenerateAssembly(runtime: null, arch: architecture, sources: new[]{cCode}, referencePaths: new[] { cSharpAssemblyPath }); await VerifyTypes(cesiumAssembly, architecture); + await VerifyAssemblyRuns(assemblyContents.ToArray(), cSharpAssemblyPath); + } + + private async Task VerifyAssemblyRuns(byte[] assemblyContentToRun, string referencePath) + { + var testDirectoryPath = Path.GetTempFileName(); + File.Delete(testDirectoryPath); + Directory.CreateDirectory(testDirectoryPath); + + try + { + var assemblyPath = Path.Combine(testDirectoryPath, "EntryPoint.dll"); + var runtimeConfigPath = Path.ChangeExtension(assemblyPath, ".runtimeconfig.json"); + + await File.WriteAllBytesAsync(assemblyPath, assemblyContentToRun); + await File.WriteAllTextAsync(runtimeConfigPath, RuntimeConfig.EmitNet7()); + + DeployReferenceAssembly(CSharpCompilationUtil.CesiumRuntimeLibraryPath); + DeployReferenceAssembly(referencePath); + + await ExecUtil.RunToSuccess(_output, "dotnet", testDirectoryPath, new[] { assemblyPath }); + } + finally + { + Directory.Delete(testDirectoryPath, recursive: true); + } + + void DeployReferenceAssembly(string assemblyPath) + { + var targetFilePath = Path.Combine(testDirectoryPath, Path.GetFileName(assemblyPath)); + File.Copy(assemblyPath, targetFilePath); + } } [Theory] @@ -41,7 +75,7 @@ public Task PointerInterop(TargetArchitectureSet architecture) => DoTest( int main(void) { int x = 0; - return Func(&x); + return Func(&x) - 1; } """); @@ -62,7 +96,7 @@ public static class Test int main(void) { int x = 0; - return Func(&x); + return Func(&x) - 1; } """); @@ -83,7 +117,7 @@ public static class Test int main(void) { int x = 0; - return Func(&x); + return Func(&x) - 1; } """); @@ -108,7 +142,7 @@ int myFunc() int main(void) { - return Func(&myFunc); + return Func(&myFunc) - 1; } """); @@ -133,7 +167,7 @@ int myFunc() int main(void) { - return Func(&myFunc); + return Func(&myFunc) - 1; } """); } diff --git a/Cesium.CodeGen.Tests/CodeGenTestBase.cs b/Cesium.CodeGen.Tests/CodeGenTestBase.cs index e92ac335..97d4887d 100644 --- a/Cesium.CodeGen.Tests/CodeGenTestBase.cs +++ b/Cesium.CodeGen.Tests/CodeGenTestBase.cs @@ -15,16 +15,28 @@ namespace Cesium.CodeGen.Tests; [UseInvariantCulture] public abstract class CodeGenTestBase : VerifyTestBase { - protected static AssemblyDefinition GenerateAssembly(TargetRuntimeDescriptor? runtime, params string[] sources) => - GenerateAssembly(sources, runtime, TargetArchitectureSet.Dynamic, "", "", Array.Empty()); + protected static AssemblyDefinition GenerateAssembly(TargetRuntimeDescriptor? runtime, params string[] sources) + { + var (assembly, _) = GenerateAssembly( + sources, + runtime, + @namespace: "", + globalTypeFqn: "", + referencePaths: Array.Empty()); + return assembly; + } + protected static AssemblyDefinition GenerateAssembly( TargetRuntimeDescriptor? runtime, TargetArchitectureSet arch = TargetArchitectureSet.Dynamic, string @namespace = "", - string globalTypeFqn = "", params string[] sources) => - GenerateAssembly(sources, runtime, arch, @namespace, globalTypeFqn, Array.Empty()); + string globalTypeFqn = "", params string[] sources) + { + var (assembly, _) = GenerateAssembly(sources, runtime, arch, @namespace, globalTypeFqn, Array.Empty()); + return assembly; + } - protected static AssemblyDefinition GenerateAssembly( + protected static (AssemblyDefinition, byte[]) GenerateAssembly( string[] sources, TargetRuntimeDescriptor? runtime = null, TargetArchitectureSet arch = TargetArchitectureSet.Dynamic, @@ -104,7 +116,7 @@ private static void GenerateCode(AssemblyContext context, IEnumerable so } } - private static AssemblyDefinition EmitAssembly(AssemblyContext context) + private static (AssemblyDefinition, byte[]) EmitAssembly(AssemblyContext context) { var assembly = context.VerifyAndGetAssembly(); @@ -112,7 +124,7 @@ private static AssemblyDefinition EmitAssembly(AssemblyContext context) using var stream = new MemoryStream(); assembly.Write(stream); - return assembly; + return (assembly, stream.ToArray()); } [MustUseReturnValue] @@ -138,7 +150,7 @@ protected static Task VerifyMethods(TypeDefinition type, params object[] paramet } [MustUseReturnValue] - protected static Task VerifyMethods(IEnumerable types, params object[] parameters) + protected static Task VerifyMethods(IEnumerable types, params object[] parameters) { var result = new StringBuilder(); int i = 0; @@ -149,7 +161,7 @@ protected static Task VerifyMethods(IEnumerable types, params ob result.AppendLine(); } - DumpMethods(type, result); + DumpMethods(type!, result); i++; } diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Dynamic.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Dynamic.verified.txt index 5cc38517..01b70310 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Dynamic.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Dynamic.verified.txt @@ -10,7 +10,9 @@ IL_0004: conv.i IL_0005: call Cesium.Runtime.CPtr`1 Cesium.Runtime.CPtr`1::op_Implicit(T*) IL_000a: call System.Int32 Test::Func(Cesium.Runtime.CPtr`1) - IL_000f: ret + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Wide.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Wide.verified.txt index 5cc38517..01b70310 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Wide.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.CPtrInterop_architecture=Wide.verified.txt @@ -10,7 +10,9 @@ IL_0004: conv.i IL_0005: call Cesium.Runtime.CPtr`1 Cesium.Runtime.CPtr`1::op_Implicit(T*) IL_000a: call System.Int32 Test::Func(Cesium.Runtime.CPtr`1) - IL_000f: ret + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Dynamic.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Dynamic.verified.txt index d58cb886..f287a68d 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Dynamic.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Dynamic.verified.txt @@ -6,11 +6,15 @@ IL_0001: ret System.Int32 ::main() - IL_0000: ldftn System.Int32 ::myFunc() - IL_0006: conv.i - IL_0007: newobj Cesium.Runtime.FuncPtr`1 Cesium.Runtime.FuncPtr`1>::.ctor(System.Void*) - IL_000c: call System.Int32 Test::Func(Cesium.Runtime.FuncPtr`1>) - IL_0011: ret + Locals: + Cesium.Runtime.FuncPtr`1> V_0 + IL_0000: ldloca V_0 + IL_0004: ldftn System.Int32 ::myFunc() + IL_000a: conv.i + IL_000b: call System.Int32 Test::Func(Cesium.Runtime.FuncPtr`1>) + IL_0010: ldc.i4.1 + IL_0011: sub + IL_0012: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Wide.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Wide.verified.txt index d58cb886..f287a68d 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Wide.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FuncPtrInterop_architecture=Wide.verified.txt @@ -6,11 +6,15 @@ IL_0001: ret System.Int32 ::main() - IL_0000: ldftn System.Int32 ::myFunc() - IL_0006: conv.i - IL_0007: newobj Cesium.Runtime.FuncPtr`1 Cesium.Runtime.FuncPtr`1>::.ctor(System.Void*) - IL_000c: call System.Int32 Test::Func(Cesium.Runtime.FuncPtr`1>) - IL_0011: ret + Locals: + Cesium.Runtime.FuncPtr`1> V_0 + IL_0000: ldloca V_0 + IL_0004: ldftn System.Int32 ::myFunc() + IL_000a: conv.i + IL_000b: call System.Int32 Test::Func(Cesium.Runtime.FuncPtr`1>) + IL_0010: ldc.i4.1 + IL_0011: sub + IL_0012: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Dynamic.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Dynamic.verified.txt index c824729d..194c527d 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Dynamic.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Dynamic.verified.txt @@ -8,7 +8,9 @@ System.Int32 ::main() IL_0000: ldftn System.Int32 ::myFunc() IL_0006: call System.Int32 Test::Func(method System.Int32 *()) - IL_000b: ret + IL_000b: ldc.i4.1 + IL_000c: sub + IL_000d: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Wide.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Wide.verified.txt index c824729d..194c527d 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Wide.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.FunctionPointerInterop_architecture=Wide.verified.txt @@ -8,7 +8,9 @@ System.Int32 ::main() IL_0000: ldftn System.Int32 ::myFunc() IL_0006: call System.Int32 Test::Func(method System.Int32 *()) - IL_000b: ret + IL_000b: ldc.i4.1 + IL_000c: sub + IL_000d: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Dynamic.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Dynamic.verified.txt index 6f882fdc..6dd62023 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Dynamic.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Dynamic.verified.txt @@ -8,7 +8,9 @@ IL_0001: stloc.0 IL_0002: ldloca.s V_0 IL_0004: call System.Int32 Test::Func(System.Int32*) - IL_0009: ret + IL_0009: ldc.i4.1 + IL_000a: sub + IL_000b: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Wide.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Wide.verified.txt index 6f882fdc..6dd62023 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Wide.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.PointerInterop_architecture=Wide.verified.txt @@ -8,7 +8,9 @@ IL_0001: stloc.0 IL_0002: ldloca.s V_0 IL_0004: call System.Int32 Test::Func(System.Int32*) - IL_0009: ret + IL_0009: ldc.i4.1 + IL_000a: sub + IL_000b: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Dynamic.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Dynamic.verified.txt index 38931ba8..15740a0e 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Dynamic.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Dynamic.verified.txt @@ -10,7 +10,9 @@ IL_0004: conv.i IL_0005: call Cesium.Runtime.VoidPtr Cesium.Runtime.VoidPtr::op_Implicit(System.Void*) IL_000a: call System.Int32 Test::Func(Cesium.Runtime.VoidPtr) - IL_000f: ret + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Wide.verified.txt b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Wide.verified.txt index 38931ba8..15740a0e 100644 --- a/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Wide.verified.txt +++ b/Cesium.CodeGen.Tests/verified/CodeGenNetInteropTests.VoidPtrInterop_architecture=Wide.verified.txt @@ -10,7 +10,9 @@ IL_0004: conv.i IL_0005: call Cesium.Runtime.VoidPtr Cesium.Runtime.VoidPtr::op_Implicit(System.Void*) IL_000a: call System.Int32 Test::Func(Cesium.Runtime.VoidPtr) - IL_000f: ret + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: ret System.Int32 ::() Locals: diff --git a/Cesium.CodeGen/Contexts/AssemblyContext.cs b/Cesium.CodeGen/Contexts/AssemblyContext.cs index 365443c0..09814bc4 100644 --- a/Cesium.CodeGen/Contexts/AssemblyContext.cs +++ b/Cesium.CodeGen/Contexts/AssemblyContext.cs @@ -137,13 +137,21 @@ TypeDefinition GetRuntimeType(string typeName) => throw new AssertException($"Could not find type {typeName} in the runtime assembly."); _runtimeCPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.CPtrFullTypeName)); - _cPtrConverterCache = new ConversionMethodCache(_runtimeCPtr, "op_Implicit", Module); + _cPtrConverterCache = new ConversionMethodCache( + _runtimeCPtr, + ReturnType: _runtimeCPtr.MakeGenericInstanceType(_runtimeCPtr.GenericParameters.Single()), + "op_Implicit", + Module); RuntimeVoidPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.VoidPtrFullTypeName)); _voidPtrConverter = new(() => GetImplicitCastOperator(TypeSystemEx.VoidPtrFullTypeName)); _runtimeFuncPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.FuncPtrFullTypeName)); - _funcPtrConstructorCache = new ConversionMethodCache(_runtimeFuncPtr, ".ctor", Module); + _funcPtrConstructorCache = new ConversionMethodCache( + _runtimeFuncPtr, + ReturnType: null, + ".ctor", + Module); _importedActionDelegates = new("System", "Action", Module); _importedFuncDelegates = new("System", "Func", Module); diff --git a/Cesium.CodeGen/Contexts/Utilities/GenericTypeCache.cs b/Cesium.CodeGen/Contexts/Utilities/ConversionMethodCache.cs similarity index 69% rename from Cesium.CodeGen/Contexts/Utilities/GenericTypeCache.cs rename to Cesium.CodeGen/Contexts/Utilities/ConversionMethodCache.cs index f4b0fa2a..38021f43 100644 --- a/Cesium.CodeGen/Contexts/Utilities/GenericTypeCache.cs +++ b/Cesium.CodeGen/Contexts/Utilities/ConversionMethodCache.cs @@ -14,6 +14,7 @@ namespace Cesium.CodeGen.Contexts.Utilities; /// internal record ConversionMethodCache( TypeReference GenericType, + TypeReference? ReturnType, string MethodName, ModuleDefinition TargetModule) { @@ -33,17 +34,11 @@ private MethodReference FindMethod(TypeReference argument) { var genericMethod = GenericType.Resolve().Methods.Single(m => m.Name == MethodName); var declaringType = GenericType.MakeGenericInstanceType(argument); - var methodReference = new MethodReference( - genericMethod.Name, - returnType: GenericType.MakeGenericInstanceType( - GenericType.GenericParameters.Single()), - declaringType); - foreach (var p in genericMethod.Parameters) - { - methodReference.Parameters.Add( - new ParameterDefinition(p.Name, p.Attributes, p.ParameterType)); - } + var methodReference = TargetModule.ImportReference(genericMethod); + methodReference.DeclaringType = declaringType; + if (ReturnType != null) + methodReference.ReturnType = ReturnType; - return TargetModule.ImportReference(methodReference); + return methodReference; } } diff --git a/Cesium.CodeGen/Ir/Expressions/TypeCastExpression.cs b/Cesium.CodeGen/Ir/Expressions/TypeCastExpression.cs index 6c525b98..b59f178b 100644 --- a/Cesium.CodeGen/Ir/Expressions/TypeCastExpression.cs +++ b/Cesium.CodeGen/Ir/Expressions/TypeCastExpression.cs @@ -29,6 +29,12 @@ public TypeCastExpression(CastExpression castExpression) public void EmitTo(IEmitScope scope) { + if (TargetType is InteropType iType) + { + iType.EmitConversion(scope, Expression); + return; + } + Expression.EmitTo(scope); var ts = scope.CTypeSystem; @@ -56,11 +62,6 @@ public void EmitTo(IEmitScope scope) Add(OpCodes.Conv_R8); else if (TargetType is PointerType || TargetType.Equals(ts.NativeInt) || TargetType.Equals(ts.NativeUInt)) Add(OpCodes.Conv_I); - else if (TargetType is InteropType iType) - { - Add(OpCodes.Conv_I); // TODO: Should only emit if required. - scope.Method.Body.Instructions.Add(iType.GetConvertInstruction(scope.AssemblyContext)); - } else throw new AssertException($"Type {TargetType} is not supported."); diff --git a/Cesium.CodeGen/Ir/Types/InteropType.cs b/Cesium.CodeGen/Ir/Types/InteropType.cs index e758ade2..eaa93783 100644 --- a/Cesium.CodeGen/Ir/Types/InteropType.cs +++ b/Cesium.CodeGen/Ir/Types/InteropType.cs @@ -1,5 +1,6 @@ using Cesium.CodeGen.Contexts; using Cesium.CodeGen.Extensions; +using Cesium.CodeGen.Ir.Expressions; using Cesium.Core; using Mono.Cecil; using Mono.Cecil.Cil; @@ -33,24 +34,46 @@ internal record InteropType(TypeReference UnderlyingType) : IType $"{nameof(InteropType)} doesn't know how to get size of an underlying {UnderlyingType}."); } - public Instruction GetConvertInstruction(AssemblyContext context) + public void EmitConversion(IEmitScope scope, IExpression expression) { + void EmitExprAndGetPtr() + { + expression.EmitTo(scope); + scope.AddInstruction(OpCodes.Conv_I); // TODO: Should only emit if required. + } + + var assemblyContext = scope.AssemblyContext; if (UnderlyingType.FullName == TypeSystemEx.VoidPtrFullTypeName) - return Instruction.Create(OpCodes.Call, context.VoidPtrConverter); + { + EmitExprAndGetPtr(); + scope.AddInstruction(OpCodes.Call, assemblyContext.VoidPtrConverter); + return; + } if (UnderlyingType is GenericInstanceType typeInstance) { var parent = typeInstance.GetElementType(); - return parent.FullName switch + switch (parent.FullName) { - TypeSystemEx.CPtrFullTypeName => - Instruction.Create(OpCodes.Call, context.CPtrConverter(typeInstance.GenericArguments.Single())), - TypeSystemEx.FuncPtrFullTypeName => + case TypeSystemEx.CPtrFullTypeName: + EmitExprAndGetPtr(); + scope.AddInstruction( + OpCodes.Call, + assemblyContext.CPtrConverter(typeInstance.GenericArguments.Single())); + break; + case TypeSystemEx.FuncPtrFullTypeName: + var funcPtrVariable = new VariableDefinition(UnderlyingType); + scope.Method.Body.Variables.Add(funcPtrVariable); + scope.AddInstruction(OpCodes.Ldloca, funcPtrVariable); // TODO: Use common mechanism to efficiently address local variables, use ldloca.s when necessary + EmitExprAndGetPtr(); Instruction.Create( - OpCodes.Newobj, - context.FuncPtrConstructor(typeInstance.GenericArguments.Single())), - _ => throw new AssertException($"No conversion available for interop type {parent}.") - }; + OpCodes.Call, + assemblyContext.FuncPtrConstructor(typeInstance.GenericArguments.Single())); + break; + default: + throw new AssertException($"No conversion available for interop type {parent}."); + } + return; } throw new AssertException( diff --git a/Cesium.Compiler/Cesium.Compiler.csproj b/Cesium.Compiler/Cesium.Compiler.csproj index 09a27547..ec2a202e 100644 --- a/Cesium.Compiler/Cesium.Compiler.csproj +++ b/Cesium.Compiler/Cesium.Compiler.csproj @@ -25,6 +25,7 @@ + diff --git a/Cesium.Compiler/RuntimeConfig.cs b/Cesium.Compiler/RuntimeConfig.cs index f5c7acf7..2b75217d 100644 --- a/Cesium.Compiler/RuntimeConfig.cs +++ b/Cesium.Compiler/RuntimeConfig.cs @@ -14,4 +14,17 @@ public static string EmitNet6() => """ } } """.ReplaceLineEndings("\n"); + + public static string EmitNet7() => """ + { + "runtimeOptions": { + "tfm": "net7.0", + "rollForward": "Major", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "7.0.0" + } + } + } + """.ReplaceLineEndings("\n"); } diff --git a/Cesium.Test.Framework/CSharpCompilationUtil.cs b/Cesium.Test.Framework/CSharpCompilationUtil.cs index db20a668..1dbf4bb7 100644 --- a/Cesium.Test.Framework/CSharpCompilationUtil.cs +++ b/Cesium.Test.Framework/CSharpCompilationUtil.cs @@ -62,9 +62,8 @@ await ExecUtil.RunToSuccess( project.Add(new XElement("PropertyGroup", new XElement(new XElement("AllowUnsafeBlocks", "true")))); - var runtimeLibraryPath = GetCesiumRuntimeLibraryPath(); project.Add(new XElement("ItemGroup", - new XElement("Reference", new XAttribute("Include", runtimeLibraryPath)))); + new XElement("Reference", new XAttribute("Include", CesiumRuntimeLibraryPath)))); await using var outputStream = new FileStream(projectFilePath, FileMode.Truncate, FileAccess.Write); await csProj.SaveAsync(outputStream, SaveOptions.None, CancellationToken.None); @@ -72,7 +71,7 @@ await ExecUtil.RunToSuccess( return projectDirectory; } - private static string GetCesiumRuntimeLibraryPath() => Path.Combine( + public static readonly string CesiumRuntimeLibraryPath = Path.Combine( TestStructureUtil.SolutionRootPath, "Cesium.Runtime", "bin",