From 85086ea11719d03e9e6a66bf934ecd7732c4fb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 18 Apr 2025 02:40:15 +0100 Subject: [PATCH 1/5] Update core library to add support for generics (#242) --- .runsettings | 5 +- Tests/NFUnitTestGC/TestGC.cs | 36 ++++++-- Tests/NFUnitTestSystemLib/UnitTestGCTest.cs | 85 ++++++++----------- .../UnitTestInitLocalTests.cs | 27 +++++- .../UnitTestReflectionTypeTest.cs | 72 ++++++++++------ .../UnitTestLauncher/UnitTestLauncher.nfproj | 2 +- azure-pipelines.yml | 3 + nanoFramework.CoreLibrary.nuspec | 7 +- .../System/AssemblyInfo.cs | 2 +- nanoFramework.CoreLibrary/System/GC.cs | 70 +++++++++++---- nanoFramework.CoreLibrary/System/Guid.cs | 5 +- nanoFramework.TestFramework | 2 +- version.json | 3 +- 13 files changed, 205 insertions(+), 114 deletions(-) diff --git a/.runsettings b/.runsettings index 3d17b679..536c73fb 100644 --- a/.runsettings +++ b/.runsettings @@ -1,4 +1,4 @@ - + @@ -12,5 +12,6 @@ Verbose False --forcegc + True - \ No newline at end of file + diff --git a/Tests/NFUnitTestGC/TestGC.cs b/Tests/NFUnitTestGC/TestGC.cs index 0bec97a8..bf52e121 100644 --- a/Tests/NFUnitTestGC/TestGC.cs +++ b/Tests/NFUnitTestGC/TestGC.cs @@ -1,7 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using nanoFramework.TestFramework; namespace NFUnitTestGC @@ -15,8 +16,6 @@ public void TestGCStress() int maxArraySize = 1024 * 32; object[] arrays = new object[600]; - // Starting TestGCStress - for (int loop = 0; loop < 100; loop++) { OutputHelper.WriteLine($"Running iteration {loop}"); @@ -24,7 +23,7 @@ public void TestGCStress() for (int i = 0; i < arrays.Length - 1;) { OutputHelper.WriteLine($"Alloc array of {maxArraySize} bytes @ pos {i}"); - arrays[i++] = new byte[maxArraySize]; ; + arrays[i++] = new byte[maxArraySize]; OutputHelper.WriteLine($"Alloc array of 64 bytes @ pos {i}"); arrays[i++] = new byte[64]; @@ -37,8 +36,35 @@ public void TestGCStress() arrays[i] = null; } } + } + + [TestMethod] + public void TestGetTotalMemory() + { + // create several objects + object[] objects = new object[100]; + + for (int i = 0; i < objects.Length; i++) + { + objects[i] = new object(); + } + + // get total memory + long totalMemory = GC.GetTotalMemory(false); + OutputHelper.WriteLine($"Total memory: {totalMemory} bytes"); + + // release objects + for (int i = 0; i < objects.Length; i++) + { + objects[i] = null; + } + + // get total memory, forcing full collection + long totalMemoryAfterCollection = GC.GetTotalMemory(true); + OutputHelper.WriteLine($"Total memory: {totalMemoryAfterCollection} bytes"); - // Completed TestGCStress + // check if memory was released + Assert.IsTrue(totalMemory > totalMemoryAfterCollection, "Memory was not released"); } } } diff --git a/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs b/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs index 05c73642..42a3e8f0 100644 --- a/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs +++ b/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs @@ -9,6 +9,11 @@ namespace NFUnitTestSystemLib [TestClass] public class UnitTestGCTest { +#pragma warning disable S1215 // this is intended to test the GC +#pragma warning disable S1854 // this is intended to test the GC +#pragma warning disable S2696 // this is intended to test the GC +#pragma warning disable S3971 // this is intended to test the GC + internal class FinalizeObject { public static FinalizeObject m_currentInstance = null; @@ -54,17 +59,20 @@ public void SystemGC1_Test() /// 6. Verify that object has been collected /// /// - // Tests ReRegisterForFinalize - // Create a FinalizeObject. + + OutputHelper.WriteLine("Tests ReRegisterForFinalize"); + OutputHelper.WriteLine("Create a FinalizeObject."); + FinalizeObject mfo = new FinalizeObject(); m_hasFinalized1 = false; m_hasFinalized2 = false; // Release reference + OutputHelper.WriteLine("Release reference"); mfo = null; - // Allow GC - GC.WaitForPendingFinalizers(); + OutputHelper.WriteLine("Allow GC"); + GC.Collect(); int sleepTime = 1000; int slept = 0; @@ -85,10 +93,10 @@ public void SystemGC1_Test() // FinalizeObject.m_currentInstance field. Setting this value // to null and forcing another garbage collection will now // cause the object to Finalize permanently. - // Reregister and allow for GC - FinalizeObject.m_currentInstance = null; - GC.WaitForPendingFinalizers(); + OutputHelper.WriteLine("Reregister and allow for GC"); + FinalizeObject.m_currentInstance = null; + GC.Collect(); sleepTime = 1000; slept = 0; @@ -119,18 +127,19 @@ public void SystemGC2_Test() /// 6. Verify that object has not been collected /// /// - // Tests SuppressFinalize - // Create a FinalizeObject. + + OutputHelper.WriteLine("Tests SuppressFinalize"); + OutputHelper.WriteLine("Create a FinalizeObject"); FinalizeObject mfo = new FinalizeObject(); m_hasFinalized1 = false; m_hasFinalized2 = false; - // Releasing + OutputHelper.WriteLine("Releasing"); GC.SuppressFinalize(mfo); mfo = null; - // Allow GC - GC.WaitForPendingFinalizers(); + OutputHelper.WriteLine("Allow GC"); + GC.Collect(); int sleepTime = 1000; int slept = 0; @@ -138,7 +147,7 @@ public void SystemGC2_Test() while (!m_hasFinalized1 && slept < sleepTime) { // force GC run caused by memory allocation - var dummyArray = new byte[1024 * 1024 * 1]; + _ = new byte[1024 * 1024 * 1]; System.Threading.Thread.Sleep(10); slept += 10; @@ -161,59 +170,35 @@ public void SystemGC3_Test() /// /// - // Tests WaitForPendingFinalizers, dependant on test 1 - // will auto-fail if test 1 fails. OutputHelper.Write("Tests WaitForPendingFinalizers, dependant on test 1"); - OutputHelper.WriteLine("will auto-fail if test 1 fails."); + OutputHelper.WriteLine("will fail if test 1 fails."); - Assert.IsTrue(m_Test1Result); + Assert.IsTrue(m_Test1Result, "Can't run this test as SystemGC1_Test has failed."); - // Create a FinalizeObject. + OutputHelper.WriteLine("Create a FinalizeObject"); FinalizeObject mfo = new FinalizeObject(); m_hasFinalized1 = false; m_hasFinalized2 = false; - // Releasing + OutputHelper.WriteLine("Releasing"); mfo = null; - int sleepTime = 1000; - int slept = 0; - - while (!m_hasFinalized1 && slept < sleepTime) - { - // force GC run caused by memory allocation - var dummyArray = new byte[1024 * 1024 * 1]; - - System.Threading.Thread.Sleep(10); - slept += 10; - } - - OutputHelper.WriteLine($"GC took {slept}"); - - // Wait for GC + OutputHelper.WriteLine("Wait for GC"); + GC.Collect(); GC.WaitForPendingFinalizers(); - // Releasing again + OutputHelper.WriteLine("Releasing again"); FinalizeObject.m_currentInstance = null; - sleepTime = 1000; - slept = 0; - - while (!m_hasFinalized2 && slept < sleepTime) - { - // force GC run caused by memory allocation - var dummyArray = new byte[1024 * 1024 * 1]; - - System.Threading.Thread.Sleep(10); - slept += 10; - } - - OutputHelper.WriteLine($"GC took {slept}"); - - // Wait for GC + OutputHelper.WriteLine("Wait for GC"); + GC.Collect(); GC.WaitForPendingFinalizers(); Assert.IsTrue(m_hasFinalized2); } } +#pragma warning restore S1215 // "GC.Collect" should not be called +#pragma warning restore S1854 // Unused assignments should be removed +#pragma warning restore S2696 // Instance members should not write to "static" fields +#pragma warning restore S3971 // "GC.SuppressFinalize" should not be called } diff --git a/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs b/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs index fea53af7..93b37f48 100644 --- a/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs +++ b/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs @@ -49,6 +49,9 @@ public void SystemType1_GetType_Test() // ConstructorInfo) // NOTE: We add the reflection items to the ArrayList to assure that they can be properly // assigned to a object container (this used to lead to a access violation) + + OutputHelper.WriteLine("Testing Int32"); + Type type = typeof(int); list.Add(type); string name = ((Type)list[i]).Name; @@ -68,12 +71,16 @@ public void SystemType1_GetType_Test() //fRes &= name.ToLower() == "mscorlib"; //i++; + OutputHelper.WriteLine("Testing NFUnitTestSystemLib.UnitTestInitLocalTests+TestObj"); + type = Type.GetType("NFUnitTestSystemLib.UnitTestInitLocalTests+TestObj"); list.Add(type); name = ((Type)list[i]).Name; Assert.AreEqual(name, "TestObj"); i++; + OutputHelper.WriteLine("Testing IEmptyInterface"); + Type iface = type.GetInterfaces()[0]; list.Add(iface); name = ((Type)list[i]).Name; @@ -81,6 +88,8 @@ public void SystemType1_GetType_Test() Assert.AreEqual(iface.Name, "IEmptyInterface"); i++; + OutputHelper.WriteLine("Testing FieldInfo"); + FieldInfo fi = type.GetField("Field1"); list.Add(fi); name = ((FieldInfo)list[i]).Name; @@ -88,6 +97,8 @@ public void SystemType1_GetType_Test() Assert.AreEqual(fi.Name, "Field1"); i++; + OutputHelper.WriteLine("Testing MethodInfo"); + MethodInfo mi = type.GetMethod("Method1"); list.Add(mi); name = ((MethodInfo)list[i]).Name; @@ -95,6 +106,8 @@ public void SystemType1_GetType_Test() Assert.AreEqual(mi.Name, "Method1"); i++; + OutputHelper.WriteLine("Testing ConstructorInfo"); + ConstructorInfo ci = type.GetConstructor(new Type[] { }); list.Add(ci); name = ((ConstructorInfo)list[i]).Name; @@ -104,7 +117,10 @@ public void SystemType1_GetType_Test() // // Now test arrays of reflection types - // + // + + OutputHelper.WriteLine("Testing Array of Type"); + Type[] types = new Type[] { typeof(int), typeof(bool), Type.GetType("NFUnitTestSystemLib.UnitTestInitLocalTests+TestObj") }; list.Add(types[2]); name = ((Type)list[i]).Name; @@ -127,6 +143,8 @@ public void SystemType1_GetType_Test() //fRes &= asms[0].GetName().Name == "Microsoft.SPOT.Platform.Tests.Systemlib2"; //i++; + OutputHelper.WriteLine("Testing Array of FieldInfo"); + FieldInfo[] fis = new FieldInfo[] { types[2].GetField("Field1"), type.GetFields()[0] }; list.Add(fis[0]); name = ((FieldInfo)list[i]).Name; @@ -134,6 +152,8 @@ public void SystemType1_GetType_Test() Assert.AreEqual(fis[0].Name, "Field1"); i++; + OutputHelper.WriteLine("Testing Array of MethodInfo"); + MethodInfo[] mis = new MethodInfo[] { type.GetMethods()[2], types[2].GetMethod("Method2", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) }; list.Add(mis[1]); name = ((MethodInfo)list[i]).Name; @@ -141,6 +161,8 @@ public void SystemType1_GetType_Test() Assert.AreEqual(mis[1].Name, "Method2"); i++; + OutputHelper.WriteLine("Testing Array of ConstructorInfo"); + ConstructorInfo[] cis = new ConstructorInfo[] { types[2].GetConstructor(new Type[] { }), typeof(TestObj).GetConstructor(new Type[] { typeof(int) }) }; list.Add(cis[0]); name = ((ConstructorInfo)list[i]).Name; @@ -148,6 +170,8 @@ public void SystemType1_GetType_Test() Assert.AreEqual(cis[0].Name, ".ctor"); i++; + OutputHelper.WriteLine("Testing Array of System.Collections.ArrayList"); + Array ar = Array.CreateInstance(typeof(Type), 3); ((IList)ar)[0] = typeof(Type); ((IList)ar)[1] = Type.GetType("System.Collections.ArrayList"); @@ -157,7 +181,6 @@ public void SystemType1_GetType_Test() Assert.AreEqual(name, "ArrayList"); Assert.AreEqual(((Type)((IList)ar)[0]).Name, "Type"); Assert.AreEqual(((Type)ar.GetValue(1)).Name, "ArrayList"); - i++; list.Clear(); } diff --git a/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs b/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs index 709f2122..471b394d 100644 --- a/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs +++ b/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs @@ -52,85 +52,103 @@ public void SystemReflectionType_RuntimeType_Test1() /// TestClass cls = new TestClass(); + OutputHelper.WriteLine("Testing Type members for a class type"); + // Test Type members for a class type Type t = cls.GetType(); Assembly asm = t.Assembly; list.Add(asm); - Assert.AreEqual(((Assembly)list[i]).GetName().Name, "NFUnitTest"); - Assert.AreEqual(asm.GetName().Name, "NFUnitTest"); - Assert.AreEqual(t.Name, "TestClass"); - Assert.AreEqual(t.FullName, "NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestClass"); + Assert.AreEqual("NFUnitTest", ((Assembly)list[i]).GetName().Name); + Assert.AreEqual("NFUnitTest", asm.GetName().Name); + Assert.AreEqual("TestClass", t.Name); + Assert.AreEqual("NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestClass", t.FullName); Assert.IsInstanceOfType(t.BaseType, typeof(object)); Assert.IsNull(t.GetElementType()); + OutputHelper.WriteLine("Testing methods of class type"); + MethodInfo[] mis = t.GetMethods(); - Assert.AreEqual(mis[0].Name, "Method1"); + Assert.AreEqual("Method1", mis[0].Name); mis = t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic); - Assert.AreEqual(mis[0].Name, "Method2"); + Assert.AreEqual("Method2", mis[0].Name); Assert.IsNotNull(t.GetMethod("Method1")); Assert.IsNotNull(t.GetMethod("Method2", BindingFlags.Instance | BindingFlags.NonPublic)); + OutputHelper.WriteLine("Testing fields of class type"); + FieldInfo[] fis = t.GetFields(); - Assert.AreEqual(fis[0].Name, "m_Field1"); + Assert.AreEqual("m_Field1", fis[0].Name); fis = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic); - Assert.AreEqual(fis[0].Name, "m_Field2"); + Assert.AreEqual("m_Field2", fis[0].Name); Assert.IsNotNull(t.GetField("m_Field1")); Assert.IsNotNull(t.GetField("m_Field2", BindingFlags.NonPublic | BindingFlags.Instance)); Assert.IsNotNull(t.GetConstructor(new Type[] { })); + OutputHelper.WriteLine("Testing interfaces of class type"); + Type[] ifaces = t.GetInterfaces(); - Assert.AreEqual(ifaces.Length, 2); - Assert.AreEqual(ifaces[0].Name, "IInterface1"); - Assert.AreEqual(ifaces[1].Name, "IInterface2"); + Assert.AreEqual(2, ifaces.Length); + Assert.AreEqual("IInterface1", ifaces[0].Name); + Assert.AreEqual("IInterface2", ifaces[1].Name); Assert.IsTrue(t.IsSubclassOf(typeof(object))); i++; + OutputHelper.WriteLine("Testing Type members for a struct valuetype"); + // test Type members for a struct valuetype TestStruct str = new TestStruct(); t = str.GetType(); asm = t.Assembly; list.Add(asm); - Assert.AreEqual(((Assembly)list[i]).GetName().Name, "NFUnitTest"); - Assert.AreEqual(asm.GetName().Name, "NFUnitTest"); - Assert.AreEqual(t.Name, "TestStruct"); - Assert.AreEqual(t.FullName, "NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestStruct"); + Assert.AreEqual("NFUnitTest", ((Assembly)list[i]).GetName().Name); + Assert.AreEqual("NFUnitTest", asm.GetName().Name); + Assert.AreEqual("TestStruct", t.Name); + Assert.AreEqual("NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestStruct", t.FullName); Assert.IsInstanceOfType(t.BaseType, typeof(ValueType)); - Assert.AreEqual(t.GetInterfaces().Length, 0); + Assert.AreEqual(0, t.GetInterfaces().Length); Assert.IsNull(t.GetElementType()); i++; + OutputHelper.WriteLine("Testing Type members for an Assembly reflection type"); + // test Type members for an Assembly reflection type //Assembly asmObj = typeof(TestClass).Assembly; //t = asmObj.GetType(); //asm = t.Assembly; //list.Add(asm); - //Assert.AreEqual(((Assembly)list[i]).GetName().Name, "mscorlib"); - //Assert.AreEqual(asm.GetName().Name, "mscorlib"); - //Assert.AreEqual(t.Name, "Assembly"); - //Assert.AreEqual(t.FullName, "System.Reflection.Assembly"); + //Assert.AreEqual("mscorlib", ((Assembly)list[i]).GetName().Name); + //Assert.AreEqual("mscorlib", asm.GetName().Name); + //Assert.AreEqual("Assembly", t.Name); + //Assert.AreEqual("System.Reflection.Assembly", t.FullName); //Assert.IsInstanceOfType(t.BaseType, typeof(Object)); - //Assert.AreEqual(t.GetInterfaces().Length, 0); + //Assert.AreEqual(0, t.GetInterfaces().Length); //Assert.IsNull(t.GetElementType()); + OutputHelper.WriteLine("Testing Type members for a MethodInfo reflection type"); + mis = typeof(TestClass).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); t = mis.GetType(); - Assert.AreEqual(t.Name, "RuntimeMethodInfo[]"); - Assert.AreEqual(t.FullName, "System.Reflection.RuntimeMethodInfo[]"); + Assert.AreEqual("RuntimeMethodInfo[]", t.Name); + Assert.AreEqual("System.Reflection.RuntimeMethodInfo[]", t.FullName); Assert.IsInstanceOfType(t.BaseType, typeof(Array)); Assert.IsTrue(t.GetInterfaces().Length > 0); - Assert.AreEqual(t.GetElementType().Name, "RuntimeMethodInfo"); + Assert.AreEqual("RuntimeMethodInfo", t.GetElementType().Name); + + OutputHelper.WriteLine("Testing Type members for a delegate"); // test Type members for a delegate Delegate del = new MyDelegate(MyDelegateImpl); t = del.GetType(); Assert.IsNotNull(t.DeclaringType); - Assert.AreEqual(t.Name, "MyDelegate"); + Assert.AreEqual("MyDelegate", t.Name); Assert.IsInstanceOfType(t.BaseType, typeof(MulticastDelegate)); + OutputHelper.WriteLine("Testing Type members for an enum"); + // test Type members for an enum TestEnum en = TestEnum.Item1; t = en.GetType(); - Assert.IsInstanceOfType(t.DeclaringType, typeof(UnitTestReflectionTypeTest)); + Assert.IsInstanceOfType(typeof(UnitTestReflectionTypeTest), t.DeclaringType); Assert.IsTrue(t.IsEnum); Assert.IsFalse(t.IsAbstract); Assert.IsFalse(t.IsClass); @@ -148,7 +166,7 @@ public void SystemReflectionType_SystemType_Test2() Assert.IsFalse(typeof(Array).IsValueType); Assert.IsTrue(typeof(TestStruct).IsValueType); Assert.IsTrue(typeof(Type).IsSubclassOf(typeof(MemberInfo))); - Assert.AreEqual(typeof(Type).GetInterfaces()[0].Name, "IReflect"); + Assert.AreEqual("IReflect", typeof(Type).GetInterfaces()[0].Name); Assert.IsTrue(typeof(MyDelegate).IsInstanceOfType(new MyDelegate(MyDelegateImpl))); // Get known type from assembly qualified type name Culture and PublicKeyToken are used by debugger to identify types diff --git a/Tests/UnitTestLauncher/UnitTestLauncher.nfproj b/Tests/UnitTestLauncher/UnitTestLauncher.nfproj index b03d676e..646eace2 100644 --- a/Tests/UnitTestLauncher/UnitTestLauncher.nfproj +++ b/Tests/UnitTestLauncher/UnitTestLauncher.nfproj @@ -27,7 +27,7 @@ - + diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 552271dd..8cf81cb4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -60,6 +60,8 @@ jobs: variables: - group: sign-client-credentials + - name: DOTNET_NOLOGO + value: true - name: buildPlatform value: 'Any CPU' - name: buildConfiguration @@ -78,6 +80,7 @@ jobs: runUnitTests: ${{ ne(variables['processPrLabels.SKIP_UNIT_TESTS'], 'true') }} unitTestRunsettings: '$(System.DefaultWorkingDirectory)\.runsettings' skipNuGetCache: true + buildComponentsUsePreview: true # rebuild CoreLibrary project to get the assembly checksum - task: MSBuild@1 diff --git a/nanoFramework.CoreLibrary.nuspec b/nanoFramework.CoreLibrary.nuspec index 63518a26..0dc517b8 100644 --- a/nanoFramework.CoreLibrary.nuspec +++ b/nanoFramework.CoreLibrary.nuspec @@ -18,12 +18,7 @@ nanoFramework C# csharp netmf netnf nanoFramework.CoreLibrary - - - - - - + diff --git a/nanoFramework.CoreLibrary/System/AssemblyInfo.cs b/nanoFramework.CoreLibrary/System/AssemblyInfo.cs index 1d1984ee..8375deaf 100644 --- a/nanoFramework.CoreLibrary/System/AssemblyInfo.cs +++ b/nanoFramework.CoreLibrary/System/AssemblyInfo.cs @@ -10,4 +10,4 @@ [assembly: AssemblyProduct(".NET nanoFramework mscorlib")] [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] -[assembly: AssemblyNativeVersion("100.5.0.24")] +[assembly: AssemblyNativeVersion("100.22.0.0")] diff --git a/nanoFramework.CoreLibrary/System/GC.cs b/nanoFramework.CoreLibrary/System/GC.cs index 13f07e8c..7746f4f3 100644 --- a/nanoFramework.CoreLibrary/System/GC.cs +++ b/nanoFramework.CoreLibrary/System/GC.cs @@ -1,39 +1,79 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + namespace System { - using Runtime.CompilerServices; - /// /// Controls the system garbage collector, a service that automatically reclaims unused memory. /// public static class GC { +#pragma warning disable S4200 // Native methods should be wrapped + + /// + /// Enables or disables the output of garbage collection messages. + /// + /// to enable the output of GC messages; otherwise, . + /// + /// + /// Enabling GC messages may not always result in output, depending on the target build options. + /// For example, RTM builds, which remove all non-essential features, may not output these messages. + /// + /// + /// This method is specific of .NET nanoFramework implementation. There is no equivalent in full .NET API. + /// + /// [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool AnyPendingFinalizers(); + public static extern void EnableGCMessages(bool enable); /// - /// Suspends the current thread until the thread that is processing the queue of finalizers has emptied that queue. + /// Retrieves the heap size excluding fragmentation. For example if the total GC heap size is 1MB and fragmentation, ie, space taken up by free objects, takes up 400kB, this API would report 600kB. A parameter indicates whether this method can wait a short interval before returning, to allow the system to collect garbage and finalize objects. /// - public static void WaitForPendingFinalizers() - { - while (AnyPendingFinalizers()) Threading.Thread.Sleep(10); - } + /// to indicate that this method can wait for garbage collection and heap compaction to occur before returning; otherwise, . + /// The heap size, in bytes, excluding fragmentation. + public static long GetTotalMemory(bool forceFullCollection) => Run(forceFullCollection); /// - /// Requests that the system not call the finalizer for the specified object. + /// Requests that the system call the finalizer for the specified object for which has previously been called. /// - /// The object that a finalizer must not be called for. + /// The object that a finalizer must be called for. + /// is . [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void SuppressFinalize(Object obj); + public static extern void ReRegisterForFinalize(object obj); + + /// + /// Forces an immediate garbage collection of all generations. + /// + /// + /// Use this method to try to reclaim all memory that is inaccessible. It performs a blocking garbage collection of all generations. + /// All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory. + /// + public static void Collect() => Run(true); /// - /// Requests that the system call the finalizer for the specified object for which SuppressFinalize has previously been called. + /// Requests that the common language runtime not call the finalizer for the specified object. /// - /// The object that a finalizer must be called for. + /// The object whose finalizer must not be executed. + /// is . [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void ReRegisterForFinalize(Object obj); + public static extern void SuppressFinalize(object obj); + /// + /// Suspends the current thread until the thread that is processing the queue of finalizers has emptied that queue. + /// + public static void WaitForPendingFinalizers() + { + while (AnyPendingFinalizers()) Threading.Thread.Sleep(10); + } + +#pragma warning restore S4200 // Native methods should be wrapped + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern bool AnyPendingFinalizers(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern uint Run(bool compactHeap); } } diff --git a/nanoFramework.CoreLibrary/System/Guid.cs b/nanoFramework.CoreLibrary/System/Guid.cs index e4e2b4f1..7536fd71 100644 --- a/nanoFramework.CoreLibrary/System/Guid.cs +++ b/nanoFramework.CoreLibrary/System/Guid.cs @@ -141,7 +141,7 @@ public Guid(string g) ArgumentNullException.ThrowIfNull(g); #pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one - if (!TryParseGuidWithDashes( + if (!TryParse( g, out this)) { @@ -322,8 +322,7 @@ private static char HexToChar(int a) /// /// The .NET nanoFramework implementation of this method only supports 'D' and 'N' format specifiers. /// - [Obsolete("This will be renamed to TryParse in a future version.")] - public static bool TryParseGuidWithDashes( + public static bool TryParse( string input, out Guid result) { diff --git a/nanoFramework.TestFramework b/nanoFramework.TestFramework index 3b48df79..18e4b3d4 160000 --- a/nanoFramework.TestFramework +++ b/nanoFramework.TestFramework @@ -1 +1 @@ -Subproject commit 3b48df792339bc0bcd0a4d6572380821781b65f0 +Subproject commit 18e4b3d4b0c6b647bc3c2a8a0d11a53c059145a7 diff --git a/version.json b/version.json index 7cad52c4..3269dd37 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.17", + "version": "2.0.0-preview.{height}", "assemblyVersion": { "precision": "build" }, @@ -11,6 +11,7 @@ "publicReleaseRefSpec": [ "^refs/heads/develop$", "^refs/heads/main$", + "^refs/heads/generics$", "^refs/heads/v\\d+(?:\\.\\d+)?$" ], "cloudBuild": { From 2bb1d2dcdc5ccee8bc59b28bd17a2e29407bccf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 21 Apr 2025 16:07:29 +0100 Subject: [PATCH 2/5] Work CI-CD - Publish to nuget now happens on build from develop branch too. --- azure-pipelines.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8cf81cb4..e40cd67f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -125,15 +125,17 @@ jobs: - template: azure-pipelines-templates/class-lib-publish.yml@templates - # create or update GitHub release ON tags from release + # create or update GitHub release ON tags - task: GithubRelease@1 condition: >- and( succeeded(), eq(variables['System.PullRequest.PullRequestId'], ''), - startsWith(variables['Build.SourceBranch'], 'refs/heads/main'), - not(contains(variables['Build.SourceBranch'], 'preview')), - eq(variables['StartReleaseCandidate'], false) + eq(variables['StartReleaseCandidate'], false), + or( + eq(variables['Build.SourceBranchName'], 'main'), + eq(variables['Build.SourceBranchName'], 'develop') + ) ) displayName: Create/Update GitHub stable release inputs: From f9a91581913e80320bd7ef00be785fa2b5071072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 21 Apr 2025 17:00:28 +0100 Subject: [PATCH 3/5] Work CI-CD - Temporary disable trigger for tags. ***NO_CI*** --- azure-pipelines.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e40cd67f..676d66d6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,10 +20,6 @@ trigger: - assets/* - nanoFramework.TestFramework/* - tags: - include: - - v* - # PR always trigger build pr: autoCancel: true From e37e4b884817ef802dda6df9ff3df7ac21890a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 21 Apr 2025 17:02:20 +0100 Subject: [PATCH 4/5] Work CI-CD - Fix parameter name. - Add branch to publish nugets from. ***NO_CI*** --- azure-pipelines.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 676d66d6..fbfe4dfd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -76,7 +76,7 @@ jobs: runUnitTests: ${{ ne(variables['processPrLabels.SKIP_UNIT_TESTS'], 'true') }} unitTestRunsettings: '$(System.DefaultWorkingDirectory)\.runsettings' skipNuGetCache: true - buildComponentsUsePreview: true + usePreviewBuild: true # rebuild CoreLibrary project to get the assembly checksum - task: MSBuild@1 @@ -119,7 +119,9 @@ jobs: parameters: nugetPackageName: 'nanoFramework.CoreLibrary.NoReflection' - - template: azure-pipelines-templates/class-lib-publish.yml@templates + - template: azure-pipelines-templates/class-lib-publish.yml@templates + parameters: + baseBranchName: 'develop' # create or update GitHub release ON tags - task: GithubRelease@1 From 6303710e27eb44bfe94e91bcfb1d89d73315c992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 30 Apr 2025 16:33:47 +0100 Subject: [PATCH 5/5] Work CI-CD - Add target for .NET Framework v4.7.2 --- nanoFramework.CoreLibrary.nuspec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nanoFramework.CoreLibrary.nuspec b/nanoFramework.CoreLibrary.nuspec index 0dc517b8..6b612a06 100644 --- a/nanoFramework.CoreLibrary.nuspec +++ b/nanoFramework.CoreLibrary.nuspec @@ -13,12 +13,14 @@ https://github.com/nanoframework/CoreLibrary images\nf-logo.png - Copyright (c) .NET Foundation and Contributors + Copyright (c) .NET Foundation and Contributors This package includes the CoreLibrary assembly for .NET nanoFramework C# projects. This package requires a target with mscorlib v$nativeVersion$ (checksum $checksum$). In case you don't need the System.Reflection API there is another NuGet package without this API. nanoFramework C# csharp netmf netnf nanoFramework.CoreLibrary + +