From 4da4bac5dabdaff75df83ed4e857a120c9bdff52 Mon Sep 17 00:00:00 2001 From: Kasper de Vries <89792927+KasperJSdeVries@users.noreply.github.com> Date: Tue, 10 May 2022 23:47:37 +0200 Subject: [PATCH] Stub generation fixes (#154) --- .../SkeletonGenerator/SkeletonTemplates.cs | 2 +- .../nanoSkeletonGenerator.cs | 28 ++- .../Core/StubsGenerationTests.cs | 189 ++++++++++++++++-- .../NativeMethodGeneration.cs | 6 + .../StubsGenerationTestNFApp.nfproj | 3 - 5 files changed, 202 insertions(+), 26 deletions(-) diff --git a/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs b/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs index 1f51fa58..95ef3da2 100644 --- a/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs +++ b/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs @@ -216,7 +216,7 @@ struct {{ClassName}} // Helper Functions to access fields of managed object // Declaration of stubs. These functions are implemented by Interop code developers {{#each Functions}} - {{#if IsStatic}}static {{/if}}{{ReturnType}} {{DeclarationForUserCode}}; + static {{ReturnType}} {{DeclarationForUserCode}}; {{/each}} }; } diff --git a/MetadataProcessor.Shared/nanoSkeletonGenerator.cs b/MetadataProcessor.Shared/nanoSkeletonGenerator.cs index f29ffeeb..230f8405 100644 --- a/MetadataProcessor.Shared/nanoSkeletonGenerator.cs +++ b/MetadataProcessor.Shared/nanoSkeletonGenerator.cs @@ -154,12 +154,14 @@ private void GenerateStubs() { // get the parameter type string parameterType = string.Empty; + string parameterTypeWORef = string.Empty; string parameterTypeClr = string.Empty; if (item.ParameterType.IsByReference) { // for ref types need an extra step to get the element type parameterType = item.ParameterType.GetElementType().ToNativeTypeAsString() + "&"; + parameterTypeWORef = item.ParameterType.GetElementType().ToNativeTypeAsString(); parameterTypeClr = item.ParameterType.GetElementType().ToCLRTypeAsString(); } else @@ -169,16 +171,24 @@ private void GenerateStubs() } // compose the function declaration - declaration.Append($"{parameterType} param{parameterIndex.ToString()}, "); + declaration.Append($"{parameterType} param{parameterIndex}, "); // compose the function call - marshallingCall.Append($"param{parameterIndex.ToString()}, "); + if (item.ParameterType.IsByReference) + { + marshallingCall.Append($"*param{parameterIndex}, "); + } + else + { + marshallingCall.Append($"param{parameterIndex}, "); + } + // compose the variable block var parameterDeclaration = new ParameterDeclaration() { Index = parameterIndex.ToString(), - Name = $"param{parameterIndex.ToString()}", + Name = $"param{parameterIndex}", }; if(item.ParameterType.IsByReference) @@ -190,10 +200,10 @@ private void GenerateStubs() parameterDeclaration.Type = parameterType; parameterDeclaration.Declaration = - $"{parameterType} {parameterDeclaration.Name};" + Environment.NewLine + - $" UINT8 heapblock{parameterIndex.ToString()}[CLR_RT_HEAP_BLOCK_SIZE];"; + $"{parameterTypeWORef} *{parameterDeclaration.Name};" + Environment.NewLine + + $" uint8_t heapblock{parameterIndex}[CLR_RT_HEAP_BLOCK_SIZE];"; - parameterDeclaration.MarshallingDeclaration = $"Interop_Marshal_{parameterTypeClr}_ByRef( stack, heapblock{(parameterIndex + (m.IsStatic ? 0 : 1)).ToString()}, {parameterDeclaration.Name} )"; + parameterDeclaration.MarshallingDeclaration = $"Interop_Marshal_{parameterTypeClr}_ByRef( stack, heapblock{parameterIndex}, {(parameterIndex + (m.IsStatic ? 0 : 1))}, {parameterDeclaration.Name} )"; } else if (item.ParameterType.IsArray) @@ -203,7 +213,7 @@ private void GenerateStubs() parameterDeclaration.Type = parameterType; parameterDeclaration.Declaration = $"{parameterType} {parameterDeclaration.Name};"; - parameterDeclaration.MarshallingDeclaration = $"Interop_Marshal_{parameterTypeClr}( stack, {(parameterIndex + (m.IsStatic ? 0 : 1)).ToString()}, {parameterDeclaration.Name} )"; + parameterDeclaration.MarshallingDeclaration = $"Interop_Marshal_{parameterTypeClr}( stack, {(parameterIndex + (m.IsStatic ? 0 : 1))}, {parameterDeclaration.Name} )"; } else { @@ -212,8 +222,8 @@ private void GenerateStubs() parameterDeclaration.Type = parameterType; parameterDeclaration.Declaration = $"{parameterType} {parameterDeclaration.Name};"; - parameterDeclaration.MarshallingDeclaration = $"Interop_Marshal_{parameterTypeClr}( stack, {(parameterIndex + (m.IsStatic ? 0 : 1)).ToString()}, {parameterDeclaration.Name} )"; - } + parameterDeclaration.MarshallingDeclaration = $"Interop_Marshal_{parameterTypeClr}( stack, {(parameterIndex + (m.IsStatic ? 0 : 1))}, {parameterDeclaration.Name} )"; + } newMethod.ParameterDeclaration.Add(parameterDeclaration); parameterIndex++; } diff --git a/MetadataProcessor.Tests/Core/StubsGenerationTests.cs b/MetadataProcessor.Tests/Core/StubsGenerationTests.cs index 3fdfc38b..6782bfc1 100644 --- a/MetadataProcessor.Tests/Core/StubsGenerationTests.cs +++ b/MetadataProcessor.Tests/Core/StubsGenerationTests.cs @@ -15,7 +15,8 @@ namespace nanoFramework.Tools.MetadataProcessor.Tests.Core [TestClass] public class StubsGenerationTests { - private const string NativeMethodGenerationDeclaration = @"void NativeMethodGeneration::NativeMethodWithReferenceParameters( uint8_t& param0, uint16_t& param1, HRESULT &hr ) + private const string NativeMethodGenerationDeclaration = + @"void NativeMethodGeneration::NativeMethodWithReferenceParameters( uint8_t& param0, uint16_t& param1, HRESULT &hr ) { (void)param0; @@ -33,8 +34,171 @@ public class StubsGenerationTests }"; + private const string NativeMarshallingMethodGenerationDeclaration = + @"HRESULT Library_StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration::NativeMethodWithReferenceParameters___VOID__BYREF_U1__BYREF_U2( CLR_RT_StackFrame& stack ) +{ + NANOCLR_HEADER(); hr = S_OK; + { + + uint8_t *param0; + uint8_t heapblock0[CLR_RT_HEAP_BLOCK_SIZE]; + NANOCLR_CHECK_HRESULT( Interop_Marshal_UINT8_ByRef( stack, heapblock0, 1, param0 ) ); + + uint16_t *param1; + uint8_t heapblock1[CLR_RT_HEAP_BLOCK_SIZE]; + NANOCLR_CHECK_HRESULT( Interop_Marshal_UINT16_ByRef( stack, heapblock1, 2, param1 ) ); + + NativeMethodGeneration::NativeMethodWithReferenceParameters( *param0, *param1, hr ); + NANOCLR_CHECK_HRESULT( hr ); + + } + NANOCLR_NOCLEANUP(); +}"; + + private const string NativeHeaderMethodGenerationDeclaration = + "static void NativeMethodWithReferenceParameters( uint8_t& param0, uint16_t& param1, HRESULT &hr );"; + + private string stubPath; + [TestMethod] public void GeneratingStubsFromNFAppTest() + { + // read generated stub file and look for the function declaration + var generatedFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.cpp"); + + Assert.IsTrue(generatedFile.Contains(NativeMethodGenerationDeclaration)); + } + + [TestMethod] + public void GeneratingMarshallingStubsFromNFAppTest() + { + var generatedFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration_mshl.cpp"); + + Assert.IsTrue(generatedFile.Contains(NativeMarshallingMethodGenerationDeclaration)); + } + + [TestMethod] + public void GeneratingHeaderStubsFromNFAppTest() + { + var generatedFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.h"); + + Assert.IsTrue(generatedFile.Contains(NativeHeaderMethodGenerationDeclaration)); + } + + private const string StaticMethodWithoutParameterHeaderGeneration = + @"static void NativeStaticMethod( HRESULT &hr );"; + private const string StaticMethodWithoutParameterMarshallGeneration = + @"HRESULT Library_StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration::NativeStaticMethod___STATIC__VOID( CLR_RT_StackFrame& stack ) +{ + NANOCLR_HEADER(); hr = S_OK; + { + + NativeMethodGeneration::NativeStaticMethod( hr ); + NANOCLR_CHECK_HRESULT( hr ); + + } + NANOCLR_NOCLEANUP(); +}"; + private const string StaticMethodWithoutParameterImplementationGeneration = + @"void NativeMethodGeneration::NativeStaticMethod( HRESULT &hr ) +{ + + (void)hr; + + + //////////////////////////////// + // implementation starts here // + + + // implementation ends here // + //////////////////////////////// + + +}"; + + [TestMethod] + public void GeneratingStaticMethodWithoutParams() + { + var generatedHeaderFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.h"); + + var generatedMarshallFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration_mshl.cpp"); + + var generatedImplementationFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.cpp"); + + Assert.IsTrue(generatedHeaderFile.Contains(StaticMethodWithoutParameterHeaderGeneration)); + Assert.IsTrue(generatedMarshallFile.Contains(StaticMethodWithoutParameterMarshallGeneration)); + Assert.IsTrue(generatedImplementationFile.Contains(StaticMethodWithoutParameterImplementationGeneration)); + } + + private const string StaticMethodHeaderGeneration = + @"static uint8_t NativeStaticMethodReturningByte( char param0, HRESULT &hr );"; + private const string StaticMethodMarshallGeneration = + @"HRESULT Library_StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration::NativeStaticMethodReturningByte___STATIC__U1__CHAR( CLR_RT_StackFrame& stack ) +{ + NANOCLR_HEADER(); hr = S_OK; + { + + char param0; + NANOCLR_CHECK_HRESULT( Interop_Marshal_CHAR( stack, 0, param0 ) ); + + uint8_t retValue = NativeMethodGeneration::NativeStaticMethodReturningByte( param0, hr ); + NANOCLR_CHECK_HRESULT( hr ); + SetResult_UINT8( stack, retValue ); + } + NANOCLR_NOCLEANUP(); +}"; + private const string StaticMethodImplementationGeneration = + @"uint8_t NativeMethodGeneration::NativeStaticMethodReturningByte( char param0, HRESULT &hr ) +{ + + (void)param0; + (void)hr; + uint8_t retValue = 0; + + //////////////////////////////// + // implementation starts here // + + + // implementation ends here // + //////////////////////////////// + + return retValue; +}"; + + [TestMethod] + public void GeneratingStaticMethod() + { + var generatedHeaderFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.h"); + + var generatedMarshallFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration_mshl.cpp"); + + var generatedImplementationFile = + File.ReadAllText( + $"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.cpp"); + + Assert.IsTrue(generatedHeaderFile.Contains(StaticMethodHeaderGeneration)); + Assert.IsTrue(generatedMarshallFile.Contains(StaticMethodMarshallGeneration)); + Assert.IsTrue(generatedImplementationFile.Contains(StaticMethodImplementationGeneration)); + } + + [TestInitialize] + public void GenerateStubs() { var loadHints = new Dictionary(StringComparer.Ordinal) { @@ -50,22 +214,22 @@ public void GeneratingStubsFromNFAppTest() var fileToParse = TestObjectHelper.GenerationNFAppFullPath; var fileToCompile = Path.ChangeExtension(fileToParse, "pe"); - + // get path where stubs will be generated - var stubPath = Path.Combine( + stubPath = Path.Combine( TestObjectHelper.TestExecutionLocation, "Stubs"); - + var assemblyDefinition = AssemblyDefinition.ReadAssembly( fileToParse, new ReaderParameters { AssemblyResolver = new LoadHintsAssemblyResolver(loadHints) }); - var assemblyBuilder = new nanoAssemblyBuilder(assemblyDefinition, classNamesToExclude, false, false); + var assemblyBuilder = new nanoAssemblyBuilder(assemblyDefinition, classNamesToExclude, false); using (var stream = File.Open( - Path.ChangeExtension(fileToCompile, "tmp"), - FileMode.Create, - FileAccess.ReadWrite)) + Path.ChangeExtension(fileToCompile, "tmp"), + FileMode.Create, + FileAccess.ReadWrite)) using (var writer = new BinaryWriter(stream)) { assemblyBuilder.Write(GetBinaryWriter(writer)); @@ -87,12 +251,11 @@ public void GeneratingStubsFromNFAppTest() false); skeletonGenerator.GenerateSkeleton(); + } - // read generated stub file and look for the function declaration - string generatedFile = File.ReadAllText($"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.cpp"); - - Assert.IsTrue(generatedFile.Contains(NativeMethodGenerationDeclaration)); - + [TestCleanup] + public void DeleteStubs() + { Directory.Delete(stubPath, true); } diff --git a/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs b/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs index 8fca1b09..137c281c 100644 --- a/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs +++ b/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs @@ -23,5 +23,11 @@ public void Method() [MethodImpl(MethodImplOptions.InternalCall)] private extern void NativeMethodWithReferenceParameters(ref byte refByteParam, ref ushort refUshortParam); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void NativeStaticMethod(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern byte NativeStaticMethodReturningByte(char charParam); } } \ No newline at end of file diff --git a/MetadataProcessor.Tests/StubsGenerationTestNFApp/StubsGenerationTestNFApp.nfproj b/MetadataProcessor.Tests/StubsGenerationTestNFApp/StubsGenerationTestNFApp.nfproj index 01ffa5ca..1ddd8500 100644 --- a/MetadataProcessor.Tests/StubsGenerationTestNFApp/StubsGenerationTestNFApp.nfproj +++ b/MetadataProcessor.Tests/StubsGenerationTestNFApp/StubsGenerationTestNFApp.nfproj @@ -16,9 +16,6 @@ StubsGenerationTestNFApp v1.0 - - True -