From ee09008c2b8910bccafb1e88a68fc59be2263595 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 16 Jan 2026 23:52:46 +0000
Subject: [PATCH 1/7] Initial plan
From 5c7908b81d9a83cbaf835937ce2fd945865d0e4e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 17 Jan 2026 00:22:59 +0000
Subject: [PATCH 2/7] Fix ILogB for Half and BFloat16 subnormal values
BitOperations.LeadingZeroCount has no ushort overload, so the
TrailingSignificand is implicitly widened to uint, adding 16 extra
leading zeros. Subtract 16 to correct for this widening.
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
---
.../System.Private.CoreLib/src/System/Half.cs | 2 +-
.../src/System/Numerics/BFloat16.cs | 2 +-
.../System.Runtime.Tests/System/HalfTests.cs | 25 +++++++++++++++++++
.../System/Numerics/BFloat16Tests.cs | 25 +++++++++++++++++++
4 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs
index 2b4b9579282fbc..b9e4226f9eefc1 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Half.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs
@@ -1532,7 +1532,7 @@ public static int ILogB(Half x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
+ return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - 16 - BiasedExponentLength);
}
return x.Exponent;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
index 7095ca0a3f10d8..63c0abe9231103 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
@@ -1189,7 +1189,7 @@ public static int ILogB(BFloat16 x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
+ return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - 16 - BiasedExponentLength);
}
return x.Exponent;
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs
index 4127a0321d3b6e..62a8d831e9fccd 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs
@@ -2244,5 +2244,30 @@ public static void RadiansToDegreesTest(Half value, Half expectedResult, Half al
AssertExtensions.Equal(-expectedResult, Half.RadiansToDegrees(-value), allowedVariance);
AssertExtensions.Equal(+expectedResult, Half.RadiansToDegrees(+value), allowedVariance);
}
+
+ [Theory]
+ [InlineData(float.PositiveInfinity, int.MaxValue)]
+ [InlineData(float.NaN, int.MaxValue)]
+ [InlineData(0.0f, int.MinValue)]
+ [InlineData(1.0f, 0)]
+ [InlineData(2.0f, 1)]
+ [InlineData(4.0f, 2)]
+ [InlineData(0.5f, -1)]
+ public static void ILogB(float value, int expectedResult)
+ {
+ Assert.Equal(expectedResult, Half.ILogB((Half)value));
+ }
+
+ [Fact]
+ public static void ILogB_Subnormal()
+ {
+ // Half.Epsilon is the smallest positive subnormal value
+ // Its ILogB should be -24 (floor(log2(5.9604645E-08)))
+ Assert.Equal(-24, Half.ILogB(Half.Epsilon));
+
+ // Test another subnormal value: 0x0200 (half of max subnormal)
+ Half subnormal = BitConverter.UInt16BitsToHalf(0x0200);
+ Assert.Equal(-15, Half.ILogB(subnormal));
+ }
}
}
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
index 041dccf8528618..2939c5b21b3f83 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
@@ -2271,6 +2271,31 @@ public static void RadiansToDegreesTest(BFloat16 value, BFloat16 expectedResult,
AssertEqual(+expectedResult, BFloat16.RadiansToDegrees(+value), allowedVariance);
}
+ [Theory]
+ [InlineData(float.PositiveInfinity, int.MaxValue)]
+ [InlineData(float.NaN, int.MaxValue)]
+ [InlineData(0.0f, int.MinValue)]
+ [InlineData(1.0f, 0)]
+ [InlineData(2.0f, 1)]
+ [InlineData(4.0f, 2)]
+ [InlineData(0.5f, -1)]
+ public static void ILogB(float value, int expectedResult)
+ {
+ Assert.Equal(expectedResult, BFloat16.ILogB((BFloat16)value));
+ }
+
+ [Fact]
+ public static void ILogB_Subnormal()
+ {
+ // BFloat16.Epsilon is the smallest positive subnormal value
+ // Its ILogB should be -133
+ Assert.Equal(-133, BFloat16.ILogB(BFloat16.Epsilon));
+
+ // Test another subnormal value: 0x0040 (half of max subnormal)
+ BFloat16 subnormal = BitConverter.UInt16BitsToBFloat16(0x0040);
+ Assert.Equal(-127, BFloat16.ILogB(subnormal));
+ }
+
#region AssertExtentions
static bool IsNegativeZero(BFloat16 value)
{
From 45b64f119b64476b6175a82eb870bbf2a92af28b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 17 Jan 2026 16:51:51 +0000
Subject: [PATCH 3/7] Add internal BitOperations.LeadingZeroCount overloads for
ushort and byte
Instead of adjusting the value at the call site, add internal overloads
of BitOperations.LeadingZeroCount for ushort and byte types that handle
the widening adjustment internally.
Update UInt16, Int16, Char, Byte, and SByte LeadingZeroCount methods to
use these new internal overloads.
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
---
.../System.Private.CoreLib/src/System/Byte.cs | 2 +-
.../System.Private.CoreLib/src/System/Char.cs | 2 +-
.../System.Private.CoreLib/src/System/Half.cs | 2 +-
.../System.Private.CoreLib/src/System/Int16.cs | 2 +-
.../src/System/Numerics/BFloat16.cs | 2 +-
.../src/System/Numerics/BitOperations.cs | 18 ++++++++++++++++++
.../System.Private.CoreLib/src/System/SByte.cs | 2 +-
.../src/System/UInt16.cs | 2 +-
8 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
index 1c933aaaced78b..575b9b4ce49729 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
@@ -279,7 +279,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) => Math.DivRem(left, right);
///
- public static byte LeadingZeroCount(byte value) => (byte)(BitOperations.LeadingZeroCount(value) - 24);
+ public static byte LeadingZeroCount(byte value) => (byte)BitOperations.LeadingZeroCount(value);
///
public static byte PopCount(byte value) => (byte)BitOperations.PopCount(value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs
index e8ee0692a82d32..0c84a326c464ae 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Char.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs
@@ -1212,7 +1212,7 @@ public static int ConvertToUtf32(string s, int index)
//
///
- static char IBinaryInteger.LeadingZeroCount(char value) => (char)(BitOperations.LeadingZeroCount(value) - 16);
+ static char IBinaryInteger.LeadingZeroCount(char value) => (char)BitOperations.LeadingZeroCount(value);
///
static char IBinaryInteger.PopCount(char value) => (char)BitOperations.PopCount(value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs
index b9e4226f9eefc1..2b4b9579282fbc 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Half.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs
@@ -1532,7 +1532,7 @@ public static int ILogB(Half x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - 16 - BiasedExponentLength);
+ return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
}
return x.Exponent;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs
index b1a90999ea5e9e..91436b18544424 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs
@@ -282,7 +282,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (short Quotient, short Remainder) DivRem(short left, short right) => Math.DivRem(left, right);
///
- public static short LeadingZeroCount(short value) => (short)(BitOperations.LeadingZeroCount((ushort)value) - 16);
+ public static short LeadingZeroCount(short value) => (short)BitOperations.LeadingZeroCount((ushort)value);
///
public static short PopCount(short value) => (short)BitOperations.PopCount((ushort)value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
index 63c0abe9231103..7095ca0a3f10d8 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
@@ -1189,7 +1189,7 @@ public static int ILogB(BFloat16 x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - 16 - BiasedExponentLength);
+ return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
}
return x.Exponent;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
index a1f35d196bca50..3310c03efc9a89 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
@@ -207,6 +207,24 @@ public static int LeadingZeroCount(uint value)
return 31 ^ Log2SoftwareFallback(value);
}
+ ///
+ /// Count the number of leading zero bits in a mask.
+ /// Similar in behavior to the x86 instruction LZCNT.
+ ///
+ /// The value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int LeadingZeroCount(ushort value)
+ => LeadingZeroCount((uint)value) - 16;
+
+ ///
+ /// Count the number of leading zero bits in a mask.
+ /// Similar in behavior to the x86 instruction LZCNT.
+ ///
+ /// The value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int LeadingZeroCount(byte value)
+ => LeadingZeroCount((uint)value) - 24;
+
///
/// Count the number of leading zero bits in a mask.
/// Similar in behavior to the x86 instruction LZCNT.
diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs
index 4ba9c4372de61b..1d25941302a7b4 100644
--- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs
@@ -285,7 +285,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) => Math.DivRem(left, right);
///
- public static sbyte LeadingZeroCount(sbyte value) => (sbyte)(BitOperations.LeadingZeroCount((byte)value) - 24);
+ public static sbyte LeadingZeroCount(sbyte value) => (sbyte)BitOperations.LeadingZeroCount((byte)value);
///
public static sbyte PopCount(sbyte value) => (sbyte)BitOperations.PopCount((byte)value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs
index 87d4f12a9a10d9..e74c77e1733884 100644
--- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs
@@ -276,7 +276,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) => Math.DivRem(left, right);
///
- public static ushort LeadingZeroCount(ushort value) => (ushort)(BitOperations.LeadingZeroCount(value) - 16);
+ public static ushort LeadingZeroCount(ushort value) => (ushort)BitOperations.LeadingZeroCount(value);
///
public static ushort PopCount(ushort value) => (ushort)BitOperations.PopCount(value);
From 361521a39993f57ac91b82089914ba6e5c4f9e44 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 19 Jan 2026 17:31:01 +0000
Subject: [PATCH 4/7] Use ushort.LeadingZeroCount instead of BitOperations
overload
Per reviewer feedback, use the existing ushort.LeadingZeroCount method
which already handles the bit-width adjustment, instead of adding new
internal overloads to BitOperations.
Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
---
.../System.Private.CoreLib/src/System/Byte.cs | 2 +-
.../System.Private.CoreLib/src/System/Char.cs | 2 +-
.../System.Private.CoreLib/src/System/Half.cs | 2 +-
.../System.Private.CoreLib/src/System/Int16.cs | 2 +-
.../src/System/Numerics/BFloat16.cs | 2 +-
.../src/System/Numerics/BitOperations.cs | 18 ------------------
.../System.Private.CoreLib/src/System/SByte.cs | 2 +-
.../src/System/UInt16.cs | 2 +-
8 files changed, 7 insertions(+), 25 deletions(-)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
index 575b9b4ce49729..1c933aaaced78b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
@@ -279,7 +279,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) => Math.DivRem(left, right);
///
- public static byte LeadingZeroCount(byte value) => (byte)BitOperations.LeadingZeroCount(value);
+ public static byte LeadingZeroCount(byte value) => (byte)(BitOperations.LeadingZeroCount(value) - 24);
///
public static byte PopCount(byte value) => (byte)BitOperations.PopCount(value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs
index 0c84a326c464ae..e8ee0692a82d32 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Char.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs
@@ -1212,7 +1212,7 @@ public static int ConvertToUtf32(string s, int index)
//
///
- static char IBinaryInteger.LeadingZeroCount(char value) => (char)BitOperations.LeadingZeroCount(value);
+ static char IBinaryInteger.LeadingZeroCount(char value) => (char)(BitOperations.LeadingZeroCount(value) - 16);
///
static char IBinaryInteger.PopCount(char value) => (char)BitOperations.PopCount(value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs
index 2b4b9579282fbc..fc6dd2bd0c423a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Half.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs
@@ -1532,7 +1532,7 @@ public static int ILogB(Half x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
+ return MinExponent - (ushort.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
}
return x.Exponent;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs
index 91436b18544424..b1a90999ea5e9e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs
@@ -282,7 +282,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (short Quotient, short Remainder) DivRem(short left, short right) => Math.DivRem(left, right);
///
- public static short LeadingZeroCount(short value) => (short)BitOperations.LeadingZeroCount((ushort)value);
+ public static short LeadingZeroCount(short value) => (short)(BitOperations.LeadingZeroCount((ushort)value) - 16);
///
public static short PopCount(short value) => (short)BitOperations.PopCount((ushort)value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
index 7095ca0a3f10d8..feb5daba014f80 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
@@ -1189,7 +1189,7 @@ public static int ILogB(BFloat16 x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
+ return MinExponent - (ushort.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
}
return x.Exponent;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
index 3310c03efc9a89..a1f35d196bca50 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
@@ -207,24 +207,6 @@ public static int LeadingZeroCount(uint value)
return 31 ^ Log2SoftwareFallback(value);
}
- ///
- /// Count the number of leading zero bits in a mask.
- /// Similar in behavior to the x86 instruction LZCNT.
- ///
- /// The value.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static int LeadingZeroCount(ushort value)
- => LeadingZeroCount((uint)value) - 16;
-
- ///
- /// Count the number of leading zero bits in a mask.
- /// Similar in behavior to the x86 instruction LZCNT.
- ///
- /// The value.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static int LeadingZeroCount(byte value)
- => LeadingZeroCount((uint)value) - 24;
-
///
/// Count the number of leading zero bits in a mask.
/// Similar in behavior to the x86 instruction LZCNT.
diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs
index 1d25941302a7b4..4ba9c4372de61b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs
@@ -285,7 +285,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) => Math.DivRem(left, right);
///
- public static sbyte LeadingZeroCount(sbyte value) => (sbyte)BitOperations.LeadingZeroCount((byte)value);
+ public static sbyte LeadingZeroCount(sbyte value) => (sbyte)(BitOperations.LeadingZeroCount((byte)value) - 24);
///
public static sbyte PopCount(sbyte value) => (sbyte)BitOperations.PopCount((byte)value);
diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs
index e74c77e1733884..87d4f12a9a10d9 100644
--- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs
@@ -276,7 +276,7 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) => Math.DivRem(left, right);
///
- public static ushort LeadingZeroCount(ushort value) => (ushort)BitOperations.LeadingZeroCount(value);
+ public static ushort LeadingZeroCount(ushort value) => (ushort)(BitOperations.LeadingZeroCount(value) - 16);
///
public static ushort PopCount(ushort value) => (ushort)BitOperations.PopCount(value);
From 6e4b90b74bb59c9dc2bf197f205e083a6599b229 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 19 Jan 2026 18:17:22 +0000
Subject: [PATCH 5/7] Merge main and use ushort.LeadingZeroCount for both Half
and BFloat16
Merged latest changes from main and updated BFloat16.ILogB to use
ushort.LeadingZeroCount consistently with Half.ILogB, since
TrailingSignificand is ushort for both types.
Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
---
src/coreclr/jit/codegencommon.cpp | 16 +-
src/coreclr/jit/codegenwasm.cpp | 129 ++++++++-
.../IL/ILImporter.Scanner.cs | 3 +-
.../DependencyAnalysis/MethodCodeNode.cs | 23 +-
src/coreclr/vm/genericdict.cpp | 48 +---
src/coreclr/vm/genericdict.h | 1 -
src/coreclr/vm/jithelpers.cpp | 2 +-
src/coreclr/vm/loongarch64/profiler.cpp | 19 +-
.../Interop.ProcFs.GetProcessInfoById.cs | 74 +++++
.../Interop.ProcFs.GetThreadInfoById.cs | 53 ++++
...rop.ProcFsStat.TryReadProcessStatusInfo.cs | 37 ---
.../TestUtilities/System/PlatformDetection.cs | 1 +
...ions.Configuration.Functional.Tests.csproj | 7 +-
.../src/System.Diagnostics.Process.csproj | 13 +-
.../src/System/Diagnostics/Process.SunOS.cs | 136 ++++++++++
.../Diagnostics/ProcessManager.SunOS.cs | 254 ++++++++++++++++++
.../System/Diagnostics/ProcessThread.SunOS.cs | 131 +++++++++
.../tests/ProcessTests.cs | 4 +-
.../src/System/Linq/SkipTake.SpeedOpt.cs | 8 +-
.../System.Private.CoreLib.Shared.projitems | 2 +-
.../CodeAnalysis/StringSyntaxAttribute.cs | 9 +
.../src/System/Environment.SunOS.cs | 3 +-
.../src/System/Numerics/BFloat16.cs | 16 +-
.../System.Runtime/ref/System.Runtime.cs | 3 +
.../StringSyntaxAttributeTests.cs | 3 +
.../System/Numerics/BFloat16Tests.cs | 60 +++++
src/mono/mono/utils/mono-codeman.c | 24 +-
src/mono/mono/utils/mono-mmap.c | 4 +-
.../corehost/browserhost/browserhost.cpp | 40 +--
src/native/corehost/browserhost/host/host.ts | 53 +++-
.../browserhost/libBrowserHost.footer.js | 46 ++--
.../corehost/browserhost/loader/assets.ts | 56 ++--
.../corehost/browserhost/loader/config.ts | 8 +
.../corehost/browserhost/loader/polyfills.ts | 96 +++----
.../Common/JavaScript/types/ems-ambient.ts | 5 +-
src/native/libs/System.Native/entrypoints.c | 3 +-
src/native/libs/System.Native/pal_io.c | 86 +++++-
src/native/libs/System.Native/pal_io.h | 42 ++-
src/native/libs/System.Native/pal_process.c | 3 +
.../pal_ecc.c | 5 +-
.../pal_rsa.c | 5 +-
.../pal_sec.c | 7 +-
src/native/minipal/memorybarrierprocesswide.c | 24 +-
src/native/package.json | 4 +-
src/native/rollup.config.defines.js | 2 +-
45 files changed, 1249 insertions(+), 319 deletions(-)
create mode 100644 src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetProcessInfoById.cs
create mode 100644 src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetThreadInfoById.cs
delete mode 100644 src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs
create mode 100644 src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
create mode 100644 src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs
create mode 100644 src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index 14732425a2f032..5b338ba948f0b2 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -2929,6 +2929,7 @@ class RegGraph
}
#endif
};
+#endif // !TARGET_WASM
// -----------------------------------------------------------------------------
// genParamStackType: Get the type that a part of a parameter passed in a
@@ -2998,6 +2999,7 @@ var_types CodeGen::genParamStackType(LclVarDsc* dsc, const ABIPassingSegment& se
}
}
+#ifndef TARGET_WASM
// -----------------------------------------------------------------------------
// genSpillOrAddRegisterParam: Handle a register parameter either by homing it
// to stack immediately, or by adding it to the register graph.
@@ -5214,6 +5216,11 @@ void CodeGen::genFnProlog()
compiler->unwindPushMaskInt(regSet.rsMaskPreSpillRegs(true));
}
#endif // TARGET_ARM
+#else // TARGET_WASM
+ regNumber initReg = REG_NA;
+ bool initRegZeroed = false;
+ bool isOSRx64Root = false;
+#endif // TARGET_WASM
unsigned extraFrameSize = 0;
@@ -5378,6 +5385,7 @@ void CodeGen::genFnProlog()
}
#endif // TARGET_ARM
+#ifndef TARGET_WASM // TODO-WASM: temporary; un-undefine as needed.
//
// Zero out the frame as needed
//
@@ -5395,23 +5403,17 @@ void CodeGen::genFnProlog()
#endif // JIT32_GCENCODER
// Set up the GS security cookie
-
genSetGSSecurityCookie(initReg, &initRegZeroed);
#ifdef PROFILING_SUPPORTED
-
// Insert a function entry callback for profiling, if requested.
// OSR methods aren't called, so don't have enter hooks.
if (!compiler->opts.IsOSR())
{
genProfilingEnterCallback(initReg, &initRegZeroed);
}
-
#endif // PROFILING_SUPPORTED
-#else // TARGET_WASM
- regNumber initReg = REG_NA;
- bool initRegZeroed = false;
-#endif // TARGET_WASM
+#endif // !TARGET_WASM
// For OSR we may have a zero-length prolog. That's not supported
// when the method must report a generics context,/ so add a nop if so.
diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp
index 1083a96ad2a2f7..64059f66026592 100644
--- a/src/coreclr/jit/codegenwasm.cpp
+++ b/src/coreclr/jit/codegenwasm.cpp
@@ -12,9 +12,11 @@
#ifdef TARGET_64BIT
static const instruction INS_I_const = INS_i64_const;
static const instruction INS_I_add = INS_i64_add;
+static const instruction INS_I_sub = INS_i64_sub;
#else // !TARGET_64BIT
static const instruction INS_I_const = INS_i32_const;
static const instruction INS_I_add = INS_i32_add;
+static const instruction INS_I_sub = INS_i32_sub;
#endif // !TARGET_64BIT
void CodeGen::genMarkLabelsForCodegen()
@@ -43,6 +45,50 @@ void CodeGen::genBeginFnProlog()
}
}
+//------------------------------------------------------------------------
+// genPushCalleeSavedRegisters: no-op since we don't need to save anything.
+//
+void CodeGen::genPushCalleeSavedRegisters()
+{
+}
+
+//------------------------------------------------------------------------
+// genAllocLclFrame: initialize the SP and FP locals.
+//
+// Arguments:
+// frameSize - Size of the frame to establish
+// initReg - Unused
+// pInitRegZeroed - Unused
+// maskArgRegsLiveIn - Unused
+//
+void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn)
+{
+ assert(compiler->compGeneratingProlog);
+ regNumber spReg = GetStackPointerReg();
+ if (spReg == REG_NA)
+ {
+ assert(!isFramePointerUsed());
+ return;
+ }
+
+ unsigned initialSPLclIndex = 0; // TODO-WASM: remove this hardcoding once we have the SP arg local.
+ unsigned spLclIndex = WasmRegToIndex(spReg);
+ assert(initialSPLclIndex == spLclIndex);
+ if (frameSize != 0)
+ {
+ GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, initialSPLclIndex);
+ GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, frameSize);
+ GetEmitter()->emitIns(INS_I_sub);
+ GetEmitter()->emitIns_I(INS_local_set, EA_PTRSIZE, spLclIndex);
+ }
+ regNumber fpReg = GetFramePointerReg();
+ if ((fpReg != REG_NA) && (fpReg != spReg))
+ {
+ GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, spLclIndex);
+ GetEmitter()->emitIns_I(INS_local_set, EA_PTRSIZE, WasmRegToIndex(fpReg));
+ }
+}
+
//------------------------------------------------------------------------
// genEnregisterOSRArgsAndLocals: enregister OSR args and locals.
//
@@ -51,9 +97,90 @@ void CodeGen::genEnregisterOSRArgsAndLocals()
unreached(); // OSR not supported on WASM.
}
+//------------------------------------------------------------------------
+// genHomeRegisterParams: place register arguments into their RA-assigned locations.
+//
+// For the WASM RA, we have a much simplified (compared to LSRA) contract of:
+// - If an argument is live on entry in a set of registers, then the RA will
+// assign those registers to that argument on entry.
+// This means we never need to do any copying or cycle resolution here.
+//
+// The main motivation for this (along with the obvious CQ implications) is
+// obviating the need to adapt the general "RegGraph"-based algorithm to
+// !HAS_FIXED_REGISTER_SET constraints (no reg masks).
+//
+// Arguments:
+// initReg - Unused
+// initRegStillZeroed - Unused
+//
void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
{
- // NYI_WASM("Un-undefine 'genHomeRegisterParams' in codegencommon.cpp and proceed from there");
+ JITDUMP("*************** In genHomeRegisterParams()\n");
+
+ auto spillParam = [this](unsigned lclNum, unsigned offset, unsigned paramLclNum, const ABIPassingSegment& segment) {
+ assert(segment.IsPassedInRegister());
+
+ LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
+ if (varDsc->lvTracked && !VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
+ {
+ return;
+ }
+
+ if (varDsc->lvOnFrame && (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr))
+ {
+ LclVarDsc* paramVarDsc = compiler->lvaGetDesc(paramLclNum);
+ var_types storeType = genParamStackType(paramVarDsc, segment);
+ if (!varDsc->TypeIs(TYP_STRUCT) && (genTypeSize(genActualType(varDsc)) < genTypeSize(storeType)))
+ {
+ // Can happen for struct fields due to padding.
+ storeType = genActualType(varDsc);
+ }
+
+ GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(GetFramePointerReg()));
+ GetEmitter()->emitIns_I(INS_local_get, emitActualTypeSize(storeType),
+ WasmRegToIndex(segment.GetRegister()));
+ GetEmitter()->emitIns_S(ins_Store(storeType), emitActualTypeSize(storeType), lclNum, offset);
+ }
+
+ if (varDsc->lvIsInReg())
+ {
+ assert(varDsc->GetRegNum() == segment.GetRegister());
+ }
+ };
+
+ for (unsigned lclNum = 0; lclNum < compiler->info.compArgsCount; lclNum++)
+ {
+ LclVarDsc* lclDsc = compiler->lvaGetDesc(lclNum);
+ const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(lclNum);
+
+ for (const ABIPassingSegment& segment : abiInfo.Segments())
+ {
+ if (!segment.IsPassedInRegister())
+ {
+ continue;
+ }
+
+ const ParameterRegisterLocalMapping* mapping =
+ compiler->FindParameterRegisterLocalMappingByRegister(segment.GetRegister());
+
+ bool spillToBaseLocal = true;
+ if (mapping != nullptr)
+ {
+ spillParam(mapping->LclNum, mapping->Offset, lclNum, segment);
+
+ // If home is shared with base local, then skip spilling to the base local.
+ if (lclDsc->lvPromoted)
+ {
+ spillToBaseLocal = false;
+ }
+ }
+
+ if (spillToBaseLocal)
+ {
+ spillParam(lclNum, segment.Offset, lclNum, segment);
+ }
+ }
+ }
}
void CodeGen::genFnEpilog(BasicBlock* block)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
index 5dc003a79f081c..49820dc03374d9 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
@@ -796,8 +796,9 @@ private void ImportCall(ILOpcode opcode, int token)
{
instParam = GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, runtimeDeterminedMethod.OwningType);
}
- else if (targetMethod.AcquiresInstMethodTableFromThis())
+ else
{
+ Debug.Assert(targetMethod.AcquiresInstMethodTableFromThis());
_dependencies.Add(_factory.ShadowNonConcreteMethod(concreteMethod), reason);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs
index 389181e6c8511c..f2853124566b34 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/MethodCodeNode.cs
@@ -260,9 +260,10 @@ public IEnumerable GetNativeSequencePoints()
if (_debugLocInfos == null)
yield break;
- var sequencePoints = new (string Document, int LineNumber)[_debugLocInfos.Length * 4 /* chosen empirically */];
+ var sequencePoints = new (string Document, int LineNumber, bool IsBackedSequencePoint)[_debugLocInfos.Length * 4 /* chosen empirically */];
try
{
+ int maxOffset = 0;
foreach (var sequencePoint in _debugInfo.GetSequencePoints())
{
int offset = sequencePoint.Offset;
@@ -271,7 +272,17 @@ public IEnumerable GetNativeSequencePoints()
int newLength = Math.Max(2 * sequencePoints.Length, sequencePoint.Offset + 1);
Array.Resize(ref sequencePoints, newLength);
}
- sequencePoints[offset] = (sequencePoint.Document, sequencePoint.LineNumber);
+ sequencePoints[offset] = (sequencePoint.Document, sequencePoint.LineNumber, true);
+ maxOffset = Math.Max(maxOffset, offset);
+ }
+
+ // Propagate last known document/line number forward to enable correct mapping when IL offsets decrease at higher native offsets
+ for (int i = 1; i <= maxOffset; i++)
+ {
+ if (sequencePoints[i].Document == null && sequencePoints[i - 1].Document != null)
+ {
+ sequencePoints[i] = (sequencePoints[i - 1].Document, sequencePoints[i - 1].LineNumber, false);
+ }
}
}
catch (BadImageFormatException)
@@ -283,6 +294,7 @@ public IEnumerable GetNativeSequencePoints()
}
int previousNativeOffset = -1;
+ int previousIlOffset = -1;
foreach (var nativeMapping in _debugLocInfos)
{
if (nativeMapping.NativeOffset == previousNativeOffset)
@@ -291,13 +303,18 @@ public IEnumerable GetNativeSequencePoints()
if (nativeMapping.ILOffset < sequencePoints.Length)
{
var sequencePoint = sequencePoints[nativeMapping.ILOffset];
- if (sequencePoint.Document != null)
+ // Emit sequence point if we have it from _debugInfo or if ILOffset decreases.
+ // This handles the case of IL offsets decreasing at higher native offsets.
+ // See WalkILOffsetsCallback in src/coreclr/vm/debugdebugger.cpp for more details.
+ if ((sequencePoint.IsBackedSequencePoint || nativeMapping.ILOffset < previousIlOffset) &&
+ sequencePoint.Document != null)
{
yield return new NativeSequencePoint(
nativeMapping.NativeOffset,
sequencePoint.Document,
sequencePoint.LineNumber);
previousNativeOffset = nativeMapping.NativeOffset;
+ previousIlOffset = nativeMapping.ILOffset;
}
}
}
diff --git a/src/coreclr/vm/genericdict.cpp b/src/coreclr/vm/genericdict.cpp
index 4e512fa7cb38f6..e9d15c0fa6bb63 100644
--- a/src/coreclr/vm/genericdict.cpp
+++ b/src/coreclr/vm/genericdict.cpp
@@ -669,7 +669,6 @@ Dictionary::PopulateEntry(
MethodDesc * pMD,
MethodTable * pMT,
LPVOID signature,
- BOOL nonExpansive,
DictionaryEntry ** ppSlot,
DWORD dictionaryIndexAndSlot, /* = -1 */
Module * pModule /* = NULL */)
@@ -811,16 +810,11 @@ Dictionary::PopulateEntry(
declaringType = ptr.GetTypeHandleThrowing(
pLookupModule,
&typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
- if (declaringType.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
IfFailThrow(ptr.SkipExactlyOne());
FALLTHROUGH;
@@ -831,16 +825,11 @@ Dictionary::PopulateEntry(
TypeHandle th = ptr.GetTypeHandleThrowing(
pLookupModule,
&typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
- if (th.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
IfFailThrow(ptr.SkipExactlyOne());
if (!declaringType.IsNull())
@@ -864,16 +853,11 @@ Dictionary::PopulateEntry(
constraintType = ptr.GetTypeHandleThrowing(
pLookupModule,
&typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
- if (constraintType.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
IfFailThrow(ptr.SkipExactlyOne());
FALLTHROUGH;
@@ -967,7 +951,6 @@ Dictionary::PopulateEntry(
if (ownerType.IsNull())
ownerType = pMethod->GetMethodTable();
- _ASSERT(!ownerType.IsNull() && !nonExpansive);
pOwnerMT = ownerType.GetMethodTable();
if (kind == DispatchStubAddrSlot && pMethod->IsVtableMethod())
@@ -981,22 +964,13 @@ Dictionary::PopulateEntry(
ownerType = ptr.GetTypeHandleThrowing(
pLookupModule,
&typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
- if (ownerType.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
IfFailThrow(ptr.SkipExactlyOne());
- // wsperf: Create a path that doesn't load types or create new handles if nonExpansive is set
- if (nonExpansive)
- return NULL;
-
pOwnerMT = ownerType.GetMethodTable();
_ASSERTE(pOwnerMT != NULL);
@@ -1026,16 +1000,11 @@ Dictionary::PopulateEntry(
TypeHandle thMethodDefType = ptr.GetTypeHandleThrowing(
pLookupModule,
&typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
- if (thMethodDefType.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
IfFailThrow(ptr.SkipExactlyOne());
MethodTable * pMethodDefMT = thMethodDefType.GetMethodTable();
_ASSERTE(pMethodDefMT != NULL);
@@ -1257,16 +1226,11 @@ Dictionary::PopulateEntry(
ownerType = ptr.GetTypeHandleThrowing(
pLookupModule,
&typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
- if (ownerType.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
IfFailThrow(ptr.SkipExactlyOne());
// Computed by MethodTable::GetIndexForFieldDesc().
diff --git a/src/coreclr/vm/genericdict.h b/src/coreclr/vm/genericdict.h
index b0cf4ee6c4b666..be2a0af5569029 100644
--- a/src/coreclr/vm/genericdict.h
+++ b/src/coreclr/vm/genericdict.h
@@ -276,7 +276,6 @@ class Dictionary
static DictionaryEntry PopulateEntry(MethodDesc * pMD,
MethodTable * pMT,
LPVOID signature,
- BOOL nonExpansive,
DictionaryEntry ** ppSlot,
DWORD dictionaryIndexAndSlot = -1,
Module * pModule = NULL);
diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp
index 0520a652ff4ac1..4a63050a9493b5 100644
--- a/src/coreclr/vm/jithelpers.cpp
+++ b/src/coreclr/vm/jithelpers.cpp
@@ -557,7 +557,7 @@ DictionaryEntry GenericHandleWorkerCore(MethodDesc * pMD, MethodTable * pMT, LPV
}
DictionaryEntry * pSlot;
- result = Dictionary::PopulateEntry(pMD, pDeclaringMT, signature, FALSE, &pSlot, dictionaryIndexAndSlot, pModule);
+ result = Dictionary::PopulateEntry(pMD, pDeclaringMT, signature, &pSlot, dictionaryIndexAndSlot, pModule);
if (pMT != NULL && pDeclaringMT != pMT)
{
diff --git a/src/coreclr/vm/loongarch64/profiler.cpp b/src/coreclr/vm/loongarch64/profiler.cpp
index 89fc2af6ddf652..588e98a9d8fa95 100644
--- a/src/coreclr/vm/loongarch64/profiler.cpp
+++ b/src/coreclr/vm/loongarch64/profiler.cpp
@@ -293,11 +293,18 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void)
return (LPVOID)pData->argumentRegisters.a[0];
}
- FpStruct::Flags fpReturnSize = FpStruct::Flags(m_argIterator.GetFPReturnSize());
-
- if (fpReturnSize != 0)
+ FpStructInRegistersInfo info = {(FpStruct::Flags)m_argIterator.GetFPReturnSize()};
+ if (info.flags != FpStruct::UseIntCallConv)
{
- if (fpReturnSize & (FpStruct::OnlyOne | FpStruct::BothFloat))
+ if ((info.flags & FpStruct::BothFloat) && ((info.flags & 0xF0) == 0xA0))
+ {
+ // For struct{single, single} case using the tail 16 bytes for return structure.
+ UINT32* dst = (UINT32*)&pData->buffer[sizeof(pData->buffer) - 16];
+ *dst = *(const UINT32*)&pData->floatArgumentRegisters.f[0];
+ *(dst + 1) = *(const UINT32*)(&pData->floatArgumentRegisters.f[1]);
+ return dst;
+ }
+ else if ((info.flags & FpStruct::OnlyOne) || (info.flags & FpStruct::BothFloat))
{
return &pData->floatArgumentRegisters.f[0];
}
@@ -310,14 +317,14 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void)
// using the tail 16 bytes for return structure.
UINT64* dst = (UINT64*)&pData->buffer[sizeof(pData->buffer) - 16];
- if (fpReturnSize & FpStruct::FloatInt)
+ if (info.flags & FpStruct::FloatInt)
{
*(double*)dst = pData->floatArgumentRegisters.f[0];
*(dst + 1) = pData->argumentRegisters.a[0];
}
else
{
- _ASSERTE(fpReturnSize & FpStruct::IntFloat);
+ _ASSERTE(info.flags & FpStruct::IntFloat);
*dst = pData->argumentRegisters.a[0];
*(double*)(dst + 1) = pData->floatArgumentRegisters.f[0];
}
diff --git a/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetProcessInfoById.cs b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetProcessInfoById.cs
new file mode 100644
index 00000000000000..0fb1f430198a08
--- /dev/null
+++ b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetProcessInfoById.cs
@@ -0,0 +1,74 @@
+// 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 System.Diagnostics;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class @procfs
+ {
+ // Constants from sys/procfs.h
+ private const int PRARGSZ = 80;
+
+ // Output type for GetProcessInfoById()
+ // Keep in sync with pal_io.h ProcessInfo
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ProcessInfo
+ {
+ internal ulong VirtualSize;
+ internal ulong ResidentSetSize;
+ internal long StartTime;
+ internal long StartTimeNsec;
+ internal long CpuTotalTime;
+ internal long CpuTotalTimeNsec;
+ internal int Pid;
+ internal int ParentPid;
+ internal int SessionId;
+ internal int Priority;
+ internal int NiceVal;
+ }
+
+ [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadProcessInfo", SetLastError = true)]
+ private static unsafe partial int ReadProcessInfo(int pid, ProcessInfo* processInfo, byte* argBuf, int argBufSize);
+
+ ///
+ /// Attempts to get status info for the specified process ID.
+ ///
+ /// PID of the process to read status info for.
+ /// The pointer to ProcessInfo instance.
+ ///
+ /// true if the process status was read; otherwise, false.
+ ///
+ internal static unsafe bool GetProcessInfoById(int pid, out ProcessInfo processInfo)
+ {
+ fixed (ProcessInfo* pProcessInfo = &processInfo)
+ {
+ if (ReadProcessInfo(pid, pProcessInfo, null, 0) < 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Variant that also gets the arg string.
+ internal static unsafe bool GetProcessInfoById(int pid, out ProcessInfo processInfo, out string argString)
+ {
+ byte* argBuf = stackalloc byte[PRARGSZ];
+ fixed (ProcessInfo* pProcessInfo = &processInfo)
+ {
+ if (ReadProcessInfo(pid, pProcessInfo, argBuf, PRARGSZ) < 0)
+ {
+ argString = "";
+ return false;
+ }
+ }
+ argString = Marshal.PtrToStringUTF8((IntPtr)argBuf)!;
+ return true;
+ }
+ }
+}
diff --git a/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetThreadInfoById.cs b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetThreadInfoById.cs
new file mode 100644
index 00000000000000..a993c89f7b9a35
--- /dev/null
+++ b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFs.GetThreadInfoById.cs
@@ -0,0 +1,53 @@
+// 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 System.Diagnostics;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class @procfs
+ {
+ // Output type for GetThreadInfoById()
+ // Keep in sync with pal_io.h ThreadInfo
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ThreadInfo
+ {
+ internal long StartTime;
+ internal long StartTimeNsec;
+ internal long CpuTotalTime; // user+sys
+ internal long CpuTotalTimeNsec;
+ internal int Tid;
+ internal int Priority;
+ internal int NiceVal;
+ internal char StatusCode;
+ }
+
+ [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadThreadInfo", SetLastError = true)]
+ private static unsafe partial int ReadThreadInfo(int pid, int tid, ThreadInfo* threadInfo);
+
+ ///
+ /// Attempts to get status info for the specified thread ID.
+ ///
+ /// PID of the process to read status info for.
+ /// TID of the thread to read status info for.
+ /// The pointer to ThreadInfo instance.
+ ///
+ /// true if the process status was read; otherwise, false.
+ ///
+ internal static unsafe bool GetThreadInfoById(int pid, int tid, out ThreadInfo threadInfo)
+ {
+ fixed (ThreadInfo* pThreadInfo = &threadInfo)
+ {
+ if (ReadThreadInfo(pid, tid, pThreadInfo) < 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs
deleted file mode 100644
index 5d835f241cda1b..00000000000000
--- a/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.InteropServices;
-
-internal static partial class Interop
-{
- internal static partial class @procfs
- {
- ///
- /// Attempts to get status info for the specified process ID.
- ///
- /// PID of the process to read status info for.
- /// The pointer to processStatus instance.
- ///
- /// true if the process status was read; otherwise, false.
- ///
- [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadProcessStatusInfo", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static unsafe partial bool TryReadProcessStatusInfo(int pid, ProcessStatusInfo* processStatus);
-
- internal struct ProcessStatusInfo
- {
- internal nuint ResidentSetSize;
- // add more fields when needed.
- }
-
- internal static unsafe bool TryReadProcessStatusInfo(int pid, out ProcessStatusInfo statusInfo)
- {
- statusInfo = default;
- fixed (ProcessStatusInfo* pStatusInfo = &statusInfo)
- {
- return TryReadProcessStatusInfo(pid, pStatusInfo);
- }
- }
- }
-}
diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
index 4b4f2b3a32ca35..3a32912136e992 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
@@ -50,6 +50,7 @@ public static partial class PlatformDetection
public static bool IsNotMacCatalyst => !IsMacCatalyst;
public static bool Isillumos => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ILLUMOS"));
public static bool IsSolaris => RuntimeInformation.IsOSPlatform(OSPlatform.Create("SOLARIS"));
+ public static bool IsSunOS => Isillumos || IsSolaris;
public static bool IsBrowser => RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
public static bool IsWasi => RuntimeInformation.IsOSPlatform(OSPlatform.Create("WASI"));
public static bool IsWasm => IsBrowser || IsWasi;
diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj
index 6effbded51d6f8..6e7e6ec9e90800 100644
--- a/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj
+++ b/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj
@@ -10,7 +10,12 @@
-
+
+
PreserveNewest
diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
index 1207ea97a10aef..6738fbbe805725 100644
--- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
+++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
@@ -1,7 +1,7 @@
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)
+ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)
$(DefineConstants);FEATURE_REGISTRY
true
false
@@ -369,6 +369,17 @@
Link="Common\Interop\FreeBSD\Interop.Process.GetProcInfo.cs" />
+
+
+
+
+
+
+
+
+
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
new file mode 100644
index 00000000000000..f40076a3882aca
--- /dev/null
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
@@ -0,0 +1,136 @@
+// 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 System.Buffers;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Text;
+using System.Threading;
+
+namespace System.Diagnostics
+{
+ public partial class Process : IDisposable
+ {
+ /// Gets the time the associated process was started.
+ internal DateTime StartTimeCore
+ {
+ get
+ {
+ Interop.procfs.ProcessInfo processInfo = GetProcInfo();
+
+ DateTime startTime = DateTime.UnixEpoch +
+ TimeSpan.FromSeconds(processInfo.StartTime) +
+ TimeSpan.FromMicroseconds(processInfo.StartTimeNsec / 1000);
+
+ // The return value is expected to be in the local time zone.
+ return startTime.ToLocalTime();
+ }
+ }
+
+ /// Gets the parent process ID
+ private int ParentProcessId => GetProcInfo().ParentPid;
+
+ /// Gets execution path
+ private static string? GetPathToOpenFile()
+ {
+ return FindProgramInPath("xdg-open");
+ }
+
+ ///
+ /// Gets the amount of time the associated process has spent utilizing the CPU.
+ /// It is the sum of the and
+ /// .
+ ///
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public TimeSpan TotalProcessorTime
+ {
+ get
+ {
+ // a.k.a. "user" + "system" time
+ Interop.procfs.ProcessInfo processInfo = GetProcInfo();
+ TimeSpan ts = TimeSpan.FromSeconds(processInfo.CpuTotalTime) +
+ TimeSpan.FromMicroseconds(processInfo.CpuTotalTimeNsec / 1000);
+ return ts;
+ }
+ }
+
+ ///
+ /// Gets the amount of time the associated process has spent running code
+ /// inside the application portion of the process (not the operating system core).
+ ///
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public TimeSpan UserProcessorTime
+ {
+ get
+ {
+ // a.k.a. "user" time
+ // Could get this from /proc/$pid/status
+ // Just say it's all user time for now
+ return TotalProcessorTime;
+ }
+ }
+
+ ///
+ /// Gets the amount of time the process has spent running code inside the operating
+ /// system core.
+ ///
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public TimeSpan PrivilegedProcessorTime
+ {
+ get
+ {
+ // a.k.a. "system" time
+ // Could get this from /proc/$pid/status
+ // Just say it's all user time for now
+ EnsureState(State.HaveNonExitedId);
+ return TimeSpan.Zero;
+ }
+ }
+
+ // ----------------------------------
+ // ---- Unix PAL layer ends here ----
+ // ----------------------------------
+
+ /// Gets the name that was used to start the process, or null if it could not be retrieved.
+ internal static string? GetUntruncatedProcessName(ref Interop.procfs.ProcessInfo processInfo, ref string argString)
+ {
+ // This assumes the process name is the first part of the Args string
+ // ending at the first space. That seems to work well enough for now.
+ // If someday this need to support a process name containing spaces,
+ // this could call a new Interop function that reads /proc/$pid/auxv
+ // (sys/auxv.h) and gets the AT_SUN_EXECNAME string from that file.
+ if (processInfo.Pid != 0 && !string.IsNullOrEmpty(argString))
+ {
+ string[] argv = argString.Split(' ', 2);
+ if (!string.IsNullOrEmpty(argv[0]))
+ {
+ return Path.GetFileName(argv[0]);
+ }
+ }
+ return null;
+ }
+
+ /// Reads the information for this process from the procfs file system.
+ private Interop.procfs.ProcessInfo GetProcInfo()
+ {
+ EnsureState(State.HaveNonExitedId);
+ Interop.procfs.ProcessInfo processInfo;
+ if (!Interop.procfs.GetProcessInfoById(_processId, out processInfo))
+ {
+ throw new Win32Exception(SR.ProcessInformationUnavailable);
+ }
+ return processInfo;
+ }
+ }
+}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs
new file mode 100644
index 00000000000000..9b8cc20ac57335
--- /dev/null
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs
@@ -0,0 +1,254 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace System.Diagnostics
+{
+ internal static partial class ProcessManager
+ {
+ /// Gets the IDs of all processes on the current machine.
+ public static int[] GetProcessIds()
+ {
+ IEnumerable pids = EnumerateProcessIds();
+ return new List(pids).ToArray();
+ }
+
+ /// Gets process infos for each process on the specified machine.
+ /// Optional process name to use as an inclusion filter.
+ /// The target machine.
+ /// An array of process infos, one per found process.
+ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName)
+ {
+ ThrowIfRemoteMachine(machineName);
+
+ // Iterate through all process IDs to load information about each process
+ IEnumerable pids = EnumerateProcessIds();
+ ArrayBuilder processes = default;
+ foreach (int pid in pids)
+ {
+ ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter);
+ if (pi != null)
+ {
+ processes.Add(pi);
+ }
+ }
+
+ return processes.ToArray();
+ }
+
+ /// Gets an array of module infos for the specified process.
+ /// The ID of the process whose modules should be enumerated.
+ /// The array of modules.
+ internal static ProcessModuleCollection GetModules(int processId)
+ {
+
+ // Negative PIDs aren't valid
+ ArgumentOutOfRangeException.ThrowIfNegative(processId);
+
+ // GetModules(x)[0].FileName is often used to find the path to the executable,
+ // so at least get that. That appears to be sufficient, at least for now.
+ // If needed, the full list of loaded modules could be obtained using another
+ // Interop function to read /proc/$pid/auxv similar to how the "pargs" and "pldd"
+ // commands do their work.
+
+ string argString;
+ Interop.procfs.ProcessInfo processInfo;
+ if (Interop.procfs.GetProcessInfoById(processId, out processInfo, out argString))
+ {
+ string? fullName = Process.GetUntruncatedProcessName(ref processInfo, ref argString);
+ if (!string.IsNullOrEmpty(fullName))
+ {
+ return new ProcessModuleCollection(1)
+ {
+ new ProcessModule(fullName, Path.GetFileName(fullName))
+ };
+ }
+ }
+ return new ProcessModuleCollection(0);
+ }
+
+ ///
+ /// Creates a ProcessInfo from the specified process ID.
+ ///
+ internal static ProcessInfo? CreateProcessInfo(int pid, string? processNameFilter = null)
+ {
+ // Negative PIDs aren't valid
+ ArgumentOutOfRangeException.ThrowIfNegative(pid);
+
+ Interop.procfs.ProcessInfo processInfo;
+ string argString;
+ if (!Interop.procfs.GetProcessInfoById(pid, out processInfo, out argString))
+ {
+ return null;
+ }
+
+ string? processName = Process.GetUntruncatedProcessName(ref processInfo, ref argString);
+ if (!string.IsNullOrEmpty(processNameFilter) &&
+ !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
+ return CreateProcessInfo(ref processInfo, ref argString);
+ }
+
+ // ----------------------------------
+ // ---- Unix PAL layer ends here ----
+ // ----------------------------------
+
+ /// Enumerates the IDs of all processes on the current machine.
+ internal static IEnumerable EnumerateProcessIds()
+ {
+ // Parse /proc for any directory that's named with a number. Each such
+ // directory represents a process.
+ const string dir = "/proc";
+ foreach (string procDir in Directory.EnumerateDirectories(dir))
+ {
+ string dirName = Path.GetFileName(procDir);
+ int pid;
+ if (int.TryParse(dirName, NumberStyles.Integer, CultureInfo.InvariantCulture, out pid))
+ {
+ Debug.Assert(pid >= 0);
+ yield return pid;
+ }
+ }
+ }
+
+ /// Enumerates the IDs of all threads in the specified process.
+ internal static IEnumerable EnumerateThreadIds(int pid)
+ {
+ // Parse /proc/$pid/lwp for any directory that's named with a number.
+ // Each such directory represents a thread.
+ string dir = $"/proc/{(uint)pid}/lwp";
+ foreach (string lwpDir in Directory.EnumerateDirectories(dir))
+ {
+ string dirName = Path.GetFileName(lwpDir);
+ int tid;
+ if (int.TryParse(dirName, NumberStyles.Integer, CultureInfo.InvariantCulture, out tid))
+ {
+ Debug.Assert(tid >= 0);
+ yield return tid;
+ }
+ }
+ }
+
+ ///
+ /// Creates a ProcessInfo from the data read from a /proc/pid/psinfo file and the associated lwp directory.
+ ///
+ internal static ProcessInfo CreateProcessInfo(ref Interop.procfs.ProcessInfo processInfo, ref string argString)
+ {
+ int pid = processInfo.Pid;
+
+ string? name = Process.GetUntruncatedProcessName(ref processInfo, ref argString);
+ if (string.IsNullOrEmpty(name)) {
+ // We were able to read the psinfo for this process, but the /proc reader
+ // found no arg string. The process exists, so rather than fail for this,
+ // just continue with a made-up arg string.
+ // Debug.Fail($"Failed to get args for proc {0:D}");
+ name = string.Format("", pid);
+ }
+
+ var pi = new ProcessInfo()
+ {
+ ProcessId = pid,
+ ProcessName = name,
+ BasePriority = processInfo.Priority,
+ SessionId = processInfo.SessionId,
+ VirtualBytes = (long)processInfo.VirtualSize,
+ WorkingSet = (long)processInfo.ResidentSetSize,
+ // StartTime: See Process.StartTimeCore()
+ };
+
+ // Then read through /proc/pid/lwp/ to find each thread in the process...
+ // Can we use a "get" method to avoid loading this for every process until it's asked for?
+ try
+ {
+
+ // Iterate through all thread IDs to load information about each thread
+ IEnumerable tids = EnumerateThreadIds(pid);
+
+ foreach (int tid in tids)
+ {
+ Interop.procfs.ThreadInfo threadInfo;
+ ThreadInfo? ti;
+
+ if (!Interop.procfs.GetThreadInfoById(pid, tid, out threadInfo))
+ {
+ continue;
+ }
+
+ ti = CreateThreadInfo(ref processInfo, ref threadInfo);
+ if (ti != null)
+ {
+ pi._threadInfoList.Add(ti);
+ }
+ }
+ }
+ catch (IOException)
+ {
+ // Between the time that we get an ID and the time that we try to read the associated
+ // directories and files in procfs, the process could be gone.
+ }
+
+ // Finally return what we've built up
+ return pi;
+ }
+
+ ///
+ /// Creates a ThreadInfo from the data read from a /proc/pid/lwp/lwpsinfo file.
+ ///
+ internal static ThreadInfo CreateThreadInfo(ref Interop.procfs.ProcessInfo processInfo,
+ ref Interop.procfs.ThreadInfo threadInfo)
+ {
+
+ var ti = new ThreadInfo()
+ {
+ _processId = processInfo.Pid,
+ _threadId = (ulong)threadInfo.Tid,
+ _basePriority = threadInfo.Priority,
+ _currentPriority = threadInfo.Priority,
+ _startAddress = null,
+ _threadState = ProcFsStateToThreadState(threadInfo.StatusCode),
+ _threadWaitReason = ThreadWaitReason.Unknown
+ };
+
+ return ti;
+ }
+
+ /// Gets a ThreadState to represent the value returned from the status field of /proc/pid/stat.
+ /// The status field value.
+ ///
+ private static ThreadState ProcFsStateToThreadState(char c)
+ {
+ // Information on these in fs/proc/array.c
+ // `man proc` does not document them all
+ switch (c)
+ {
+ case 'O': // On-CPU
+ case 'R': // Runnable
+ return ThreadState.Running;
+
+ case 'S': // Sleeping in a wait
+ case 'T': // Stopped on a signal
+ return ThreadState.Wait;
+
+ case 'Z': // Zombie
+ return ThreadState.Terminated;
+
+ case 'W': // Waiting for CPU
+ return ThreadState.Transition;
+
+ case '\0': // new, not started yet
+ return ThreadState.Initialized;
+
+ default:
+ Debug.Fail($"Unexpected status character: {(int)c}");
+ return ThreadState.Unknown;
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs
new file mode 100644
index 00000000000000..4f585dce18aee3
--- /dev/null
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs
@@ -0,0 +1,131 @@
+// 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.Versioning;
+
+namespace System.Diagnostics
+{
+ public partial class ProcessThread
+ {
+ /// Gets the time this thread was started.
+ internal DateTime GetStartTime()
+ {
+ Interop.procfs.ThreadInfo threadInfo = GetThreadInfo();
+
+ DateTime startTime = DateTime.UnixEpoch +
+ TimeSpan.FromSeconds(threadInfo.StartTime) +
+ TimeSpan.FromMicroseconds(threadInfo.StartTimeNsec / 1000);
+
+ // The return value is expected to be in the local time zone.
+ return startTime.ToLocalTime();
+ }
+
+ ///
+ /// Returns or sets the priority level of the associated thread. The priority level is
+ /// not an absolute level, but instead contributes to the actual thread priority by
+ /// considering the priority class of the process.
+ ///
+ private ThreadPriorityLevel PriorityLevelCore
+ {
+ get
+ {
+ Interop.procfs.ThreadInfo threadInfo = GetThreadInfo();
+ return GetThreadPriorityFromSysPri(threadInfo.Priority);
+ }
+ set
+ {
+ // Raising priority is a privileged operation.
+ // Might be able to adjust our "nice" value. Maybe later...
+ throw new PlatformNotSupportedException();
+ }
+ }
+
+ ///
+ /// Gets the amount of time the associated thread has spent utilizing the CPU.
+ /// It is the sum of the System.Diagnostics.ProcessThread.UserProcessorTime and
+ /// System.Diagnostics.ProcessThread.PrivilegedProcessorTime.
+ ///
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public TimeSpan TotalProcessorTime
+ {
+ get
+ {
+ // a.k.a. "user" + "system" time
+ Interop.procfs.ThreadInfo threadInfo = GetThreadInfo();
+ TimeSpan ts = TimeSpan.FromSeconds(threadInfo.CpuTotalTime) +
+ TimeSpan.FromMicroseconds(threadInfo.CpuTotalTimeNsec / 1000);
+ return ts;
+ }
+ }
+
+ ///
+ /// Gets the amount of time the associated thread has spent running code
+ /// inside the application (not the operating system core).
+ ///
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public TimeSpan UserProcessorTime
+ {
+ get
+ {
+ // a.k.a. "user" time
+ // Could get this from /proc/$pid/lwp/$lwpid/lwpstatus
+ // Just say it's all user time for now
+ return TotalProcessorTime;
+ }
+ }
+
+ ///
+ /// Gets the amount of time the thread has spent running code inside the operating
+ /// system core.
+ ///
+ [UnsupportedOSPlatform("ios")]
+ [UnsupportedOSPlatform("tvos")]
+ [SupportedOSPlatform("maccatalyst")]
+ public TimeSpan PrivilegedProcessorTime
+ {
+ get
+ {
+ // a.k.a. "system" time
+ // Could get this from /proc/$pid/lwp/$lwpid/lwpstatus
+ // Just say it's all user time for now
+ return TimeSpan.Zero;
+ }
+
+ }
+
+ // ----------------------------------
+ // ---- exported stuff ends here ----
+ // ----------------------------------
+
+ // System priorities go from 1 to 100, where 60 and above are for "system" things
+ // These mappingsare relatively arbitrary. Normal user processes run at priority 59.
+ // and the other values above and below are simply distributed somewhat evenly.
+ private static System.Diagnostics.ThreadPriorityLevel GetThreadPriorityFromSysPri(int pri)
+ {
+ Debug.Assert((pri >= 0) && (pri <= 100));
+ return
+ (pri >= 90) ? ThreadPriorityLevel.TimeCritical :
+ (pri >= 80) ? ThreadPriorityLevel.Highest :
+ (pri >= 60) ? ThreadPriorityLevel.AboveNormal :
+ (pri == 59) ? ThreadPriorityLevel.Normal :
+ (pri >= 40) ? ThreadPriorityLevel.BelowNormal :
+ (pri >= 20) ? ThreadPriorityLevel.Lowest :
+ ThreadPriorityLevel.Idle;
+ }
+
+ /// Reads the information for this thread from the procfs file system.
+ private Interop.procfs.ThreadInfo GetThreadInfo()
+ {
+ Interop.procfs.ThreadInfo threadInfo;
+ if (!Interop.procfs.GetThreadInfoById(_processId, tid: Id, out threadInfo))
+ {
+ throw new InvalidOperationException(SR.Format(SR.ThreadExited, Id));
+ }
+ return threadInfo;
+ }
+ }
+}
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
index 086ad89f0d53ad..901cfcfa78a024 100644
--- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
@@ -652,7 +652,7 @@ public void TestMaxWorkingSet()
Assert.InRange((long)p.MinWorkingSet, 0, long.MaxValue);
}
- if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD()) {
+ if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD() || PlatformDetection.IsSunOS) {
return; // doesn't support getting/setting working set for other processes
}
@@ -700,7 +700,7 @@ public void TestMinWorkingSet()
Assert.InRange((long)p.MinWorkingSet, 0, long.MaxValue);
}
- if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD()) {
+ if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD() || PlatformDetection.IsSunOS) {
return; // doesn't support getting/setting working set for other processes
}
diff --git a/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs
index 944e0fa4cda70e..0a98b5c88473ca 100644
--- a/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs
+++ b/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs
@@ -441,8 +441,14 @@ public override Iterator Take(int count)
{
if (_source is Iterator iterator &&
iterator.GetCount(onlyIfCheap: true) is int count &&
- count > _minIndexInclusive)
+ count >= 0)
{
+ if (count <= _minIndexInclusive)
+ {
+ found = false;
+ return default;
+ }
+
// If there's no upper bound, or if there are fewer items in the list
// than the upper bound allows, just return the last element of the list.
// Otherwise, get the element at the upper bound.
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index d30c305a7e6fae..e2766fbc58a8d4 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -2661,7 +2661,7 @@
-
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
index 26fcf5ca096408..66c5f9b3fc4f24 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
@@ -38,6 +38,9 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments)
/// The syntax identifier for strings containing composite formats for string formatting.
public const string CompositeFormat = nameof(CompositeFormat);
+ /// The syntax identifier for strings containing C# code.
+ public const string CSharp = "C#";
+
/// The syntax identifier for strings containing date format specifiers.
public const string DateOnlyFormat = nameof(DateOnlyFormat);
@@ -47,6 +50,9 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments)
/// The syntax identifier for strings containing format specifiers.
public const string EnumFormat = nameof(EnumFormat);
+ /// The syntax identifier for strings containing F# code.
+ public const string FSharp = "F#";
+
/// The syntax identifier for strings containing format specifiers.
public const string GuidFormat = nameof(GuidFormat);
@@ -68,6 +74,9 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments)
/// The syntax identifier for strings containing URIs.
public const string Uri = nameof(Uri);
+ /// The syntax identifier for strings containing Visual Basic code.
+ public const string VisualBasic = "Visual Basic";
+
/// The syntax identifier for strings containing XML.
public const string Xml = nameof(Xml);
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs
index fb7ff75cb2e6c6..50a2150ffa613d 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs
@@ -7,7 +7,6 @@ namespace System
{
public static partial class Environment
{
- public static long WorkingSet =>
- (long)(Interop.procfs.TryReadProcessStatusInfo(ProcessId, out Interop.procfs.ProcessStatusInfo status) ? status.ResidentSetSize : 0);
+ public static long WorkingSet => (long)(Interop.procfs.GetProcessInfoById(ProcessId, out Interop.procfs.ProcessInfo iProcInfo) ? iProcInfo.ResidentSetSize : 0);
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
index feb5daba014f80..2d543808fd031a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
@@ -116,11 +116,11 @@ internal sbyte Exponent
}
}
- internal ushort Significand
+ internal byte Significand
{
get
{
- return (ushort)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U));
+ return (byte)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U));
}
}
@@ -1010,7 +1010,7 @@ int IFloatingPoint.GetExponentShortestBitLength()
}
///
- int IFloatingPoint.GetSignificandByteCount() => sizeof(ushort);
+ int IFloatingPoint.GetSignificandByteCount() => sizeof(byte);
///
int IFloatingPoint.GetSignificandBitLength() => SignificandLength;
@@ -1046,9 +1046,10 @@ bool IFloatingPoint.TryWriteExponentLittleEndian(Span destinatio
///
bool IFloatingPoint.TryWriteSignificandBigEndian(Span destination, out int bytesWritten)
{
- if (BinaryPrimitives.TryWriteUInt16BigEndian(destination, Significand))
+ if (destination.Length >= sizeof(byte))
{
- bytesWritten = sizeof(uint);
+ destination[0] = Significand;
+ bytesWritten = sizeof(byte);
return true;
}
@@ -1059,9 +1060,10 @@ bool IFloatingPoint.TryWriteSignificandBigEndian(Span destinatio
///
bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destination, out int bytesWritten)
{
- if (BinaryPrimitives.TryWriteUInt16LittleEndian(destination, Significand))
+ if (destination.Length >= sizeof(byte))
{
- bytesWritten = sizeof(uint);
+ destination[0] = Significand;
+ bytesWritten = sizeof(byte);
return true;
}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index ce6380fc645bf2..16fcc5f730823d 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -9096,9 +9096,11 @@ public SetsRequiredMembersAttribute() { }
public sealed partial class StringSyntaxAttribute : System.Attribute
{
public const string CompositeFormat = "CompositeFormat";
+ public const string CSharp = "C#";
public const string DateOnlyFormat = "DateOnlyFormat";
public const string DateTimeFormat = "DateTimeFormat";
public const string EnumFormat = "EnumFormat";
+ public const string FSharp = "F#";
public const string GuidFormat = "GuidFormat";
public const string Json = "Json";
public const string NumericFormat = "NumericFormat";
@@ -9106,6 +9108,7 @@ public sealed partial class StringSyntaxAttribute : System.Attribute
public const string TimeOnlyFormat = "TimeOnlyFormat";
public const string TimeSpanFormat = "TimeSpanFormat";
public const string Uri = "Uri";
+ public const string VisualBasic = "Visual Basic";
public const string Xml = "Xml";
public StringSyntaxAttribute(string syntax) { }
public StringSyntaxAttribute(string syntax, params object?[] arguments) { }
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs
index ba53ab2c0f3bbe..251156cf037986 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs
@@ -8,9 +8,12 @@ namespace System.Diagnostics.CodeAnalysis.Tests
public sealed class StringSyntaxAttributeTests
{
[Theory]
+ [InlineData(StringSyntaxAttribute.CSharp)]
[InlineData(StringSyntaxAttribute.DateTimeFormat)]
+ [InlineData(StringSyntaxAttribute.FSharp)]
[InlineData(StringSyntaxAttribute.Json)]
[InlineData(StringSyntaxAttribute.Regex)]
+ [InlineData(StringSyntaxAttribute.VisualBasic)]
public void Ctor_Roundtrips(string syntax)
{
var attribute = new StringSyntaxAttribute(syntax);
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
index 2939c5b21b3f83..08597497d80b3a 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
@@ -2296,6 +2296,66 @@ public static void ILogB_Subnormal()
Assert.Equal(-127, BFloat16.ILogB(subnormal));
}
+ public static IEnumerable
-
-
+
PreserveNewest
diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
index 6738fbbe805725..1207ea97a10aef 100644
--- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
+++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
@@ -1,7 +1,7 @@
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)
+ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)
$(DefineConstants);FEATURE_REGISTRY
true
false
@@ -369,17 +369,6 @@
Link="Common\Interop\FreeBSD\Interop.Process.GetProcInfo.cs" />
-
-
-
-
-
-
-
-
-
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
deleted file mode 100644
index f40076a3882aca..00000000000000
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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 System.Buffers;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Globalization;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-using System.Text;
-using System.Threading;
-
-namespace System.Diagnostics
-{
- public partial class Process : IDisposable
- {
- /// Gets the time the associated process was started.
- internal DateTime StartTimeCore
- {
- get
- {
- Interop.procfs.ProcessInfo processInfo = GetProcInfo();
-
- DateTime startTime = DateTime.UnixEpoch +
- TimeSpan.FromSeconds(processInfo.StartTime) +
- TimeSpan.FromMicroseconds(processInfo.StartTimeNsec / 1000);
-
- // The return value is expected to be in the local time zone.
- return startTime.ToLocalTime();
- }
- }
-
- /// Gets the parent process ID
- private int ParentProcessId => GetProcInfo().ParentPid;
-
- /// Gets execution path
- private static string? GetPathToOpenFile()
- {
- return FindProgramInPath("xdg-open");
- }
-
- ///
- /// Gets the amount of time the associated process has spent utilizing the CPU.
- /// It is the sum of the and
- /// .
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
- {
- get
- {
- // a.k.a. "user" + "system" time
- Interop.procfs.ProcessInfo processInfo = GetProcInfo();
- TimeSpan ts = TimeSpan.FromSeconds(processInfo.CpuTotalTime) +
- TimeSpan.FromMicroseconds(processInfo.CpuTotalTimeNsec / 1000);
- return ts;
- }
- }
-
- ///
- /// Gets the amount of time the associated process has spent running code
- /// inside the application portion of the process (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
- {
- get
- {
- // a.k.a. "user" time
- // Could get this from /proc/$pid/status
- // Just say it's all user time for now
- return TotalProcessorTime;
- }
- }
-
- ///
- /// Gets the amount of time the process has spent running code inside the operating
- /// system core.
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
- {
- get
- {
- // a.k.a. "system" time
- // Could get this from /proc/$pid/status
- // Just say it's all user time for now
- EnsureState(State.HaveNonExitedId);
- return TimeSpan.Zero;
- }
- }
-
- // ----------------------------------
- // ---- Unix PAL layer ends here ----
- // ----------------------------------
-
- /// Gets the name that was used to start the process, or null if it could not be retrieved.
- internal static string? GetUntruncatedProcessName(ref Interop.procfs.ProcessInfo processInfo, ref string argString)
- {
- // This assumes the process name is the first part of the Args string
- // ending at the first space. That seems to work well enough for now.
- // If someday this need to support a process name containing spaces,
- // this could call a new Interop function that reads /proc/$pid/auxv
- // (sys/auxv.h) and gets the AT_SUN_EXECNAME string from that file.
- if (processInfo.Pid != 0 && !string.IsNullOrEmpty(argString))
- {
- string[] argv = argString.Split(' ', 2);
- if (!string.IsNullOrEmpty(argv[0]))
- {
- return Path.GetFileName(argv[0]);
- }
- }
- return null;
- }
-
- /// Reads the information for this process from the procfs file system.
- private Interop.procfs.ProcessInfo GetProcInfo()
- {
- EnsureState(State.HaveNonExitedId);
- Interop.procfs.ProcessInfo processInfo;
- if (!Interop.procfs.GetProcessInfoById(_processId, out processInfo))
- {
- throw new Win32Exception(SR.ProcessInformationUnavailable);
- }
- return processInfo;
- }
- }
-}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs
deleted file mode 100644
index 9b8cc20ac57335..00000000000000
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs
+++ /dev/null
@@ -1,254 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace System.Diagnostics
-{
- internal static partial class ProcessManager
- {
- /// Gets the IDs of all processes on the current machine.
- public static int[] GetProcessIds()
- {
- IEnumerable pids = EnumerateProcessIds();
- return new List(pids).ToArray();
- }
-
- /// Gets process infos for each process on the specified machine.
- /// Optional process name to use as an inclusion filter.
- /// The target machine.
- /// An array of process infos, one per found process.
- public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName)
- {
- ThrowIfRemoteMachine(machineName);
-
- // Iterate through all process IDs to load information about each process
- IEnumerable pids = EnumerateProcessIds();
- ArrayBuilder processes = default;
- foreach (int pid in pids)
- {
- ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter);
- if (pi != null)
- {
- processes.Add(pi);
- }
- }
-
- return processes.ToArray();
- }
-
- /// Gets an array of module infos for the specified process.
- /// The ID of the process whose modules should be enumerated.
- /// The array of modules.
- internal static ProcessModuleCollection GetModules(int processId)
- {
-
- // Negative PIDs aren't valid
- ArgumentOutOfRangeException.ThrowIfNegative(processId);
-
- // GetModules(x)[0].FileName is often used to find the path to the executable,
- // so at least get that. That appears to be sufficient, at least for now.
- // If needed, the full list of loaded modules could be obtained using another
- // Interop function to read /proc/$pid/auxv similar to how the "pargs" and "pldd"
- // commands do their work.
-
- string argString;
- Interop.procfs.ProcessInfo processInfo;
- if (Interop.procfs.GetProcessInfoById(processId, out processInfo, out argString))
- {
- string? fullName = Process.GetUntruncatedProcessName(ref processInfo, ref argString);
- if (!string.IsNullOrEmpty(fullName))
- {
- return new ProcessModuleCollection(1)
- {
- new ProcessModule(fullName, Path.GetFileName(fullName))
- };
- }
- }
- return new ProcessModuleCollection(0);
- }
-
- ///
- /// Creates a ProcessInfo from the specified process ID.
- ///
- internal static ProcessInfo? CreateProcessInfo(int pid, string? processNameFilter = null)
- {
- // Negative PIDs aren't valid
- ArgumentOutOfRangeException.ThrowIfNegative(pid);
-
- Interop.procfs.ProcessInfo processInfo;
- string argString;
- if (!Interop.procfs.GetProcessInfoById(pid, out processInfo, out argString))
- {
- return null;
- }
-
- string? processName = Process.GetUntruncatedProcessName(ref processInfo, ref argString);
- if (!string.IsNullOrEmpty(processNameFilter) &&
- !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- return CreateProcessInfo(ref processInfo, ref argString);
- }
-
- // ----------------------------------
- // ---- Unix PAL layer ends here ----
- // ----------------------------------
-
- /// Enumerates the IDs of all processes on the current machine.
- internal static IEnumerable EnumerateProcessIds()
- {
- // Parse /proc for any directory that's named with a number. Each such
- // directory represents a process.
- const string dir = "/proc";
- foreach (string procDir in Directory.EnumerateDirectories(dir))
- {
- string dirName = Path.GetFileName(procDir);
- int pid;
- if (int.TryParse(dirName, NumberStyles.Integer, CultureInfo.InvariantCulture, out pid))
- {
- Debug.Assert(pid >= 0);
- yield return pid;
- }
- }
- }
-
- /// Enumerates the IDs of all threads in the specified process.
- internal static IEnumerable EnumerateThreadIds(int pid)
- {
- // Parse /proc/$pid/lwp for any directory that's named with a number.
- // Each such directory represents a thread.
- string dir = $"/proc/{(uint)pid}/lwp";
- foreach (string lwpDir in Directory.EnumerateDirectories(dir))
- {
- string dirName = Path.GetFileName(lwpDir);
- int tid;
- if (int.TryParse(dirName, NumberStyles.Integer, CultureInfo.InvariantCulture, out tid))
- {
- Debug.Assert(tid >= 0);
- yield return tid;
- }
- }
- }
-
- ///
- /// Creates a ProcessInfo from the data read from a /proc/pid/psinfo file and the associated lwp directory.
- ///
- internal static ProcessInfo CreateProcessInfo(ref Interop.procfs.ProcessInfo processInfo, ref string argString)
- {
- int pid = processInfo.Pid;
-
- string? name = Process.GetUntruncatedProcessName(ref processInfo, ref argString);
- if (string.IsNullOrEmpty(name)) {
- // We were able to read the psinfo for this process, but the /proc reader
- // found no arg string. The process exists, so rather than fail for this,
- // just continue with a made-up arg string.
- // Debug.Fail($"Failed to get args for proc {0:D}");
- name = string.Format("", pid);
- }
-
- var pi = new ProcessInfo()
- {
- ProcessId = pid,
- ProcessName = name,
- BasePriority = processInfo.Priority,
- SessionId = processInfo.SessionId,
- VirtualBytes = (long)processInfo.VirtualSize,
- WorkingSet = (long)processInfo.ResidentSetSize,
- // StartTime: See Process.StartTimeCore()
- };
-
- // Then read through /proc/pid/lwp/ to find each thread in the process...
- // Can we use a "get" method to avoid loading this for every process until it's asked for?
- try
- {
-
- // Iterate through all thread IDs to load information about each thread
- IEnumerable tids = EnumerateThreadIds(pid);
-
- foreach (int tid in tids)
- {
- Interop.procfs.ThreadInfo threadInfo;
- ThreadInfo? ti;
-
- if (!Interop.procfs.GetThreadInfoById(pid, tid, out threadInfo))
- {
- continue;
- }
-
- ti = CreateThreadInfo(ref processInfo, ref threadInfo);
- if (ti != null)
- {
- pi._threadInfoList.Add(ti);
- }
- }
- }
- catch (IOException)
- {
- // Between the time that we get an ID and the time that we try to read the associated
- // directories and files in procfs, the process could be gone.
- }
-
- // Finally return what we've built up
- return pi;
- }
-
- ///
- /// Creates a ThreadInfo from the data read from a /proc/pid/lwp/lwpsinfo file.
- ///
- internal static ThreadInfo CreateThreadInfo(ref Interop.procfs.ProcessInfo processInfo,
- ref Interop.procfs.ThreadInfo threadInfo)
- {
-
- var ti = new ThreadInfo()
- {
- _processId = processInfo.Pid,
- _threadId = (ulong)threadInfo.Tid,
- _basePriority = threadInfo.Priority,
- _currentPriority = threadInfo.Priority,
- _startAddress = null,
- _threadState = ProcFsStateToThreadState(threadInfo.StatusCode),
- _threadWaitReason = ThreadWaitReason.Unknown
- };
-
- return ti;
- }
-
- /// Gets a ThreadState to represent the value returned from the status field of /proc/pid/stat.
- /// The status field value.
- ///
- private static ThreadState ProcFsStateToThreadState(char c)
- {
- // Information on these in fs/proc/array.c
- // `man proc` does not document them all
- switch (c)
- {
- case 'O': // On-CPU
- case 'R': // Runnable
- return ThreadState.Running;
-
- case 'S': // Sleeping in a wait
- case 'T': // Stopped on a signal
- return ThreadState.Wait;
-
- case 'Z': // Zombie
- return ThreadState.Terminated;
-
- case 'W': // Waiting for CPU
- return ThreadState.Transition;
-
- case '\0': // new, not started yet
- return ThreadState.Initialized;
-
- default:
- Debug.Fail($"Unexpected status character: {(int)c}");
- return ThreadState.Unknown;
- }
- }
- }
-}
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs
deleted file mode 100644
index 4f585dce18aee3..00000000000000
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessThread.SunOS.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-// 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.Versioning;
-
-namespace System.Diagnostics
-{
- public partial class ProcessThread
- {
- /// Gets the time this thread was started.
- internal DateTime GetStartTime()
- {
- Interop.procfs.ThreadInfo threadInfo = GetThreadInfo();
-
- DateTime startTime = DateTime.UnixEpoch +
- TimeSpan.FromSeconds(threadInfo.StartTime) +
- TimeSpan.FromMicroseconds(threadInfo.StartTimeNsec / 1000);
-
- // The return value is expected to be in the local time zone.
- return startTime.ToLocalTime();
- }
-
- ///
- /// Returns or sets the priority level of the associated thread. The priority level is
- /// not an absolute level, but instead contributes to the actual thread priority by
- /// considering the priority class of the process.
- ///
- private ThreadPriorityLevel PriorityLevelCore
- {
- get
- {
- Interop.procfs.ThreadInfo threadInfo = GetThreadInfo();
- return GetThreadPriorityFromSysPri(threadInfo.Priority);
- }
- set
- {
- // Raising priority is a privileged operation.
- // Might be able to adjust our "nice" value. Maybe later...
- throw new PlatformNotSupportedException();
- }
- }
-
- ///
- /// Gets the amount of time the associated thread has spent utilizing the CPU.
- /// It is the sum of the System.Diagnostics.ProcessThread.UserProcessorTime and
- /// System.Diagnostics.ProcessThread.PrivilegedProcessorTime.
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan TotalProcessorTime
- {
- get
- {
- // a.k.a. "user" + "system" time
- Interop.procfs.ThreadInfo threadInfo = GetThreadInfo();
- TimeSpan ts = TimeSpan.FromSeconds(threadInfo.CpuTotalTime) +
- TimeSpan.FromMicroseconds(threadInfo.CpuTotalTimeNsec / 1000);
- return ts;
- }
- }
-
- ///
- /// Gets the amount of time the associated thread has spent running code
- /// inside the application (not the operating system core).
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan UserProcessorTime
- {
- get
- {
- // a.k.a. "user" time
- // Could get this from /proc/$pid/lwp/$lwpid/lwpstatus
- // Just say it's all user time for now
- return TotalProcessorTime;
- }
- }
-
- ///
- /// Gets the amount of time the thread has spent running code inside the operating
- /// system core.
- ///
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("tvos")]
- [SupportedOSPlatform("maccatalyst")]
- public TimeSpan PrivilegedProcessorTime
- {
- get
- {
- // a.k.a. "system" time
- // Could get this from /proc/$pid/lwp/$lwpid/lwpstatus
- // Just say it's all user time for now
- return TimeSpan.Zero;
- }
-
- }
-
- // ----------------------------------
- // ---- exported stuff ends here ----
- // ----------------------------------
-
- // System priorities go from 1 to 100, where 60 and above are for "system" things
- // These mappingsare relatively arbitrary. Normal user processes run at priority 59.
- // and the other values above and below are simply distributed somewhat evenly.
- private static System.Diagnostics.ThreadPriorityLevel GetThreadPriorityFromSysPri(int pri)
- {
- Debug.Assert((pri >= 0) && (pri <= 100));
- return
- (pri >= 90) ? ThreadPriorityLevel.TimeCritical :
- (pri >= 80) ? ThreadPriorityLevel.Highest :
- (pri >= 60) ? ThreadPriorityLevel.AboveNormal :
- (pri == 59) ? ThreadPriorityLevel.Normal :
- (pri >= 40) ? ThreadPriorityLevel.BelowNormal :
- (pri >= 20) ? ThreadPriorityLevel.Lowest :
- ThreadPriorityLevel.Idle;
- }
-
- /// Reads the information for this thread from the procfs file system.
- private Interop.procfs.ThreadInfo GetThreadInfo()
- {
- Interop.procfs.ThreadInfo threadInfo;
- if (!Interop.procfs.GetThreadInfoById(_processId, tid: Id, out threadInfo))
- {
- throw new InvalidOperationException(SR.Format(SR.ThreadExited, Id));
- }
- return threadInfo;
- }
- }
-}
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
index 901cfcfa78a024..086ad89f0d53ad 100644
--- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
@@ -652,7 +652,7 @@ public void TestMaxWorkingSet()
Assert.InRange((long)p.MinWorkingSet, 0, long.MaxValue);
}
- if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD() || PlatformDetection.IsSunOS) {
+ if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD()) {
return; // doesn't support getting/setting working set for other processes
}
@@ -700,7 +700,7 @@ public void TestMinWorkingSet()
Assert.InRange((long)p.MinWorkingSet, 0, long.MaxValue);
}
- if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD() || PlatformDetection.IsSunOS) {
+ if (OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD()) {
return; // doesn't support getting/setting working set for other processes
}
diff --git a/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs
index 0a98b5c88473ca..944e0fa4cda70e 100644
--- a/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs
+++ b/src/libraries/System.Linq/src/System/Linq/SkipTake.SpeedOpt.cs
@@ -441,14 +441,8 @@ public override Iterator Take(int count)
{
if (_source is Iterator iterator &&
iterator.GetCount(onlyIfCheap: true) is int count &&
- count >= 0)
+ count > _minIndexInclusive)
{
- if (count <= _minIndexInclusive)
- {
- found = false;
- return default;
- }
-
// If there's no upper bound, or if there are fewer items in the list
// than the upper bound allows, just return the last element of the list.
// Otherwise, get the element at the upper bound.
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index e2766fbc58a8d4..d30c305a7e6fae 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -2661,7 +2661,7 @@
-
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
index 66c5f9b3fc4f24..26fcf5ca096408 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
@@ -38,9 +38,6 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments)
/// The syntax identifier for strings containing composite formats for string formatting.
public const string CompositeFormat = nameof(CompositeFormat);
- /// The syntax identifier for strings containing C# code.
- public const string CSharp = "C#";
-
/// The syntax identifier for strings containing date format specifiers.
public const string DateOnlyFormat = nameof(DateOnlyFormat);
@@ -50,9 +47,6 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments)
/// The syntax identifier for strings containing format specifiers.
public const string EnumFormat = nameof(EnumFormat);
- /// The syntax identifier for strings containing F# code.
- public const string FSharp = "F#";
-
/// The syntax identifier for strings containing format specifiers.
public const string GuidFormat = nameof(GuidFormat);
@@ -74,9 +68,6 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments)
/// The syntax identifier for strings containing URIs.
public const string Uri = nameof(Uri);
- /// The syntax identifier for strings containing Visual Basic code.
- public const string VisualBasic = "Visual Basic";
-
/// The syntax identifier for strings containing XML.
public const string Xml = nameof(Xml);
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs
index 50a2150ffa613d..fb7ff75cb2e6c6 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs
@@ -7,6 +7,7 @@ namespace System
{
public static partial class Environment
{
- public static long WorkingSet => (long)(Interop.procfs.GetProcessInfoById(ProcessId, out Interop.procfs.ProcessInfo iProcInfo) ? iProcInfo.ResidentSetSize : 0);
+ public static long WorkingSet =>
+ (long)(Interop.procfs.TryReadProcessStatusInfo(ProcessId, out Interop.procfs.ProcessStatusInfo status) ? status.ResidentSetSize : 0);
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
index 2d543808fd031a..feb5daba014f80 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
@@ -116,11 +116,11 @@ internal sbyte Exponent
}
}
- internal byte Significand
+ internal ushort Significand
{
get
{
- return (byte)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U));
+ return (ushort)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U));
}
}
@@ -1010,7 +1010,7 @@ int IFloatingPoint.GetExponentShortestBitLength()
}
///
- int IFloatingPoint.GetSignificandByteCount() => sizeof(byte);
+ int IFloatingPoint.GetSignificandByteCount() => sizeof(ushort);
///
int IFloatingPoint.GetSignificandBitLength() => SignificandLength;
@@ -1046,10 +1046,9 @@ bool IFloatingPoint.TryWriteExponentLittleEndian(Span destinatio
///
bool IFloatingPoint.TryWriteSignificandBigEndian(Span destination, out int bytesWritten)
{
- if (destination.Length >= sizeof(byte))
+ if (BinaryPrimitives.TryWriteUInt16BigEndian(destination, Significand))
{
- destination[0] = Significand;
- bytesWritten = sizeof(byte);
+ bytesWritten = sizeof(uint);
return true;
}
@@ -1060,10 +1059,9 @@ bool IFloatingPoint.TryWriteSignificandBigEndian(Span destinatio
///
bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destination, out int bytesWritten)
{
- if (destination.Length >= sizeof(byte))
+ if (BinaryPrimitives.TryWriteUInt16LittleEndian(destination, Significand))
{
- destination[0] = Significand;
- bytesWritten = sizeof(byte);
+ bytesWritten = sizeof(uint);
return true;
}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 16fcc5f730823d..ce6380fc645bf2 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -9096,11 +9096,9 @@ public SetsRequiredMembersAttribute() { }
public sealed partial class StringSyntaxAttribute : System.Attribute
{
public const string CompositeFormat = "CompositeFormat";
- public const string CSharp = "C#";
public const string DateOnlyFormat = "DateOnlyFormat";
public const string DateTimeFormat = "DateTimeFormat";
public const string EnumFormat = "EnumFormat";
- public const string FSharp = "F#";
public const string GuidFormat = "GuidFormat";
public const string Json = "Json";
public const string NumericFormat = "NumericFormat";
@@ -9108,7 +9106,6 @@ public sealed partial class StringSyntaxAttribute : System.Attribute
public const string TimeOnlyFormat = "TimeOnlyFormat";
public const string TimeSpanFormat = "TimeSpanFormat";
public const string Uri = "Uri";
- public const string VisualBasic = "Visual Basic";
public const string Xml = "Xml";
public StringSyntaxAttribute(string syntax) { }
public StringSyntaxAttribute(string syntax, params object?[] arguments) { }
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs
index 251156cf037986..ba53ab2c0f3bbe 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs
@@ -8,12 +8,9 @@ namespace System.Diagnostics.CodeAnalysis.Tests
public sealed class StringSyntaxAttributeTests
{
[Theory]
- [InlineData(StringSyntaxAttribute.CSharp)]
[InlineData(StringSyntaxAttribute.DateTimeFormat)]
- [InlineData(StringSyntaxAttribute.FSharp)]
[InlineData(StringSyntaxAttribute.Json)]
[InlineData(StringSyntaxAttribute.Regex)]
- [InlineData(StringSyntaxAttribute.VisualBasic)]
public void Ctor_Roundtrips(string syntax)
{
var attribute = new StringSyntaxAttribute(syntax);
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
index 08597497d80b3a..2939c5b21b3f83 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs
@@ -2296,66 +2296,6 @@ public static void ILogB_Subnormal()
Assert.Equal(-127, BFloat16.ILogB(subnormal));
}
- public static IEnumerable TryWriteSignificandBigEndianTest_TestData() =>
- [
- [BFloat16.NegativeInfinity, 1, new byte[] { 0x80 }],
- [BFloat16.MinValue, 1, new byte[] { 0xFF }],
- [(BFloat16)(-1.0f), 1, new byte[] { 0x80 }],
- [-BFloat16.Epsilon, 1, new byte[] { 0x01 }],
- [BFloat16.NaN, 1, new byte[] { 0xC0 }],
- [(BFloat16)0.0f, 1, new byte[] { 0x00 }],
- [(BFloat16)1.0f, 1, new byte[] { 0x80 }],
- [BFloat16.MaxValue, 1, new byte[] { 0xFF }],
- [BFloat16.PositiveInfinity, 1, new byte[] { 0x80 }],
- ];
-
- [Theory]
- [MemberData(nameof(TryWriteSignificandBigEndianTest_TestData))]
- public static void TryWriteSignificandBigEndianTest(BFloat16 value, int expectedBytesWritten, byte[] expectedBytes)
- {
- Span destination = [0];
- Assert.True(FloatingPointHelper.TryWriteSignificandBigEndian(value, destination, out int bytesWritten));
- Assert.Equal(expectedBytesWritten, bytesWritten);
- Assert.Equal(expectedBytes, destination.ToArray());
- }
-
- [Fact]
- public static void TryWriteSignificandBigEndianTest_EmptyDestination()
- {
- Assert.False(FloatingPointHelper.TryWriteSignificandBigEndian(default, Span.Empty, out int bytesWritten));
- Assert.Equal(0, bytesWritten);
- }
-
- public static IEnumerable TryWriteSignificandLittleEndianTest_TestData() =>
- [
- [BFloat16.NegativeInfinity, 1, new byte[] { 0x80 }],
- [BFloat16.MinValue, 1, new byte[] { 0xFF }],
- [(BFloat16)(-1.0f), 1, new byte[] { 0x80 }],
- [-BFloat16.Epsilon, 1, new byte[] { 0x01 }],
- [BFloat16.NaN, 1, new byte[] { 0xC0 }],
- [(BFloat16)0.0f, 1, new byte[] { 0x00 }],
- [(BFloat16)1.0f, 1, new byte[] { 0x80 }],
- [BFloat16.MaxValue, 1, new byte[] { 0xFF }],
- [BFloat16.PositiveInfinity, 1, new byte[] { 0x80 }],
- ];
-
- [Theory]
- [MemberData(nameof(TryWriteSignificandLittleEndianTest_TestData))]
- public static void TryWriteSignificandLittleEndianTest(BFloat16 value, int expectedBytesWritten, byte[] expectedBytes)
- {
- Span destination = [0];
- Assert.True(FloatingPointHelper.TryWriteSignificandLittleEndian(value, destination, out int bytesWritten));
- Assert.Equal(expectedBytesWritten, bytesWritten);
- Assert.Equal(expectedBytes, destination.ToArray());
- }
-
- [Fact]
- public static void TryWriteSignificandLittleEndianTest_EmptyDestination()
- {
- Assert.False(FloatingPointHelper.TryWriteSignificandLittleEndian(default, Span.Empty, out int bytesWritten));
- Assert.Equal(0, bytesWritten);
- }
-
#region AssertExtentions
static bool IsNegativeZero(BFloat16 value)
{
diff --git a/src/mono/mono/utils/mono-codeman.c b/src/mono/mono/utils/mono-codeman.c
index c655d04c8ccbea..26f8715c61dd0b 100644
--- a/src/mono/mono/utils/mono-codeman.c
+++ b/src/mono/mono/utils/mono-codeman.c
@@ -735,10 +735,12 @@ mono_codeman_enable_write (void)
if (codeman_no_exec)
return;
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
- int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id));
- level ++;
- mono_native_tls_set_value (write_level_tls_id, GINT_TO_POINTER (level));
- pthread_jit_write_protect_np (0);
+ if (__builtin_available (macOS 11, *)) {
+ int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id));
+ level ++;
+ mono_native_tls_set_value (write_level_tls_id, GINT_TO_POINTER (level));
+ pthread_jit_write_protect_np (0);
+ }
#elif defined(HOST_MACCAT) && defined(__aarch64__)
/* JITing in Catalyst apps is not allowed on Apple Silicon, so assume if we're here we don't really have executable pages. */
#endif
@@ -756,12 +758,14 @@ mono_codeman_disable_write (void)
if (codeman_no_exec)
return;
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
- int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id));
- g_assert (level);
- level --;
- mono_native_tls_set_value (write_level_tls_id, GINT_TO_POINTER (level));
- if (level == 0)
- pthread_jit_write_protect_np (1);
+ if (__builtin_available (macOS 11, *)) {
+ int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id));
+ g_assert (level);
+ level --;
+ mono_native_tls_set_value (write_level_tls_id, GINT_TO_POINTER (level));
+ if (level == 0)
+ pthread_jit_write_protect_np (1);
+ }
#elif defined(HOST_MACCAT) && defined(__aarch64__)
/* JITing in Catalyst apps is not allowed on Apple Silicon, so assume if we're here we don't really have executable pages */
#endif
diff --git a/src/mono/mono/utils/mono-mmap.c b/src/mono/mono/utils/mono-mmap.c
index fe7db3bbaf3b8a..09af6f8994b942 100644
--- a/src/mono/mono/utils/mono-mmap.c
+++ b/src/mono/mono/utils/mono-mmap.c
@@ -285,7 +285,9 @@ mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
mflags |= MAP_JIT;
#if defined(HOST_ARM64) && !defined(HOST_MACCAT)
/* Patching code on apple silicon seems to cause random crashes without this flag */
- mflags |= MAP_JIT;
+ /* No __builtin_available in old versions of Xcode that could be building Mono on x86 or amd64 */
+ if (__builtin_available (macOS 11, *))
+ mflags |= MAP_JIT;
#endif
}
#endif
diff --git a/src/native/corehost/browserhost/browserhost.cpp b/src/native/corehost/browserhost/browserhost.cpp
index 78ce28e62ec153..14d26f295d1df6 100644
--- a/src/native/corehost/browserhost/browserhost.cpp
+++ b/src/native/corehost/browserhost/browserhost.cpp
@@ -89,20 +89,44 @@ static const void* pinvoke_override(const char* library_name, const char* entry_
return nullptr;
}
-static host_runtime_contract host_contract = { sizeof(host_runtime_contract), nullptr };
-
-extern "C" void* BrowserHost_CreateHostContract(void)
+static pal::string_t app_path;
+static pal::string_t search_paths;
+static pal::string_t tpa;
+static const pal::string_t app_domain_name = "corehost";
+static const pal::string_t exe_path = "/managed";
+static std::vector propertyKeys;
+static std::vector propertyValues;
+static pal::char_t ptr_to_string_buffer[STRING_LENGTH("0xffffffffffffffff") + 1];
+
+// WASM-TODO: pass TPA via argument, not env
+// WASM-TODO: pass app_path via argument, not env
+// WASM-TODO: pass search_paths via argument, not env
+extern "C" int BrowserHost_InitializeCoreCLR(void)
{
+ pal::getenv(HOST_PROPERTY_APP_PATHS, &app_path);
+ pal::getenv(HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES, &search_paths);
+ pal::getenv(HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES, &tpa);
+
+ // Set base initialization properties.
+ propertyKeys.push_back(HOST_PROPERTY_APP_PATHS);
+ propertyValues.push_back(app_path.c_str());
+ propertyKeys.push_back(HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES);
+ propertyValues.push_back(search_paths.c_str());
+ propertyKeys.push_back(HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES);
+ propertyValues.push_back(tpa.c_str());
+
+ host_runtime_contract host_contract = { sizeof(host_runtime_contract), nullptr };
host_contract.pinvoke_override = &pinvoke_override;
host_contract.external_assembly_probe = &BrowserHost_ExternalAssemblyProbe;
- return &host_contract;
-}
-extern "C" int BrowserHost_InitializeCoreCLR(int propertiesCount, const char** propertyKeys, const char** propertyValues)
-{
+ pal::snwprintf(ptr_to_string_buffer, ARRAY_SIZE(ptr_to_string_buffer), _X("0x%zx"), (size_t)(&host_contract));
+
+ propertyKeys.push_back(HOST_PROPERTY_RUNTIME_CONTRACT);
+ propertyValues.push_back(ptr_to_string_buffer);
+
coreclr_set_error_writer(log_error_info);
- int retval = coreclr_initialize("/managed", "corehost", propertiesCount, propertyKeys, propertyValues, &CurrentClrInstance, &CurrentAppDomainId);
+ int retval = coreclr_initialize(exe_path.c_str(), app_domain_name.c_str(), (int)propertyKeys.size(), propertyKeys.data(), propertyValues.data(), &CurrentClrInstance, &CurrentAppDomainId);
if (retval < 0)
{
diff --git a/src/native/corehost/browserhost/host/host.ts b/src/native/corehost/browserhost/host/host.ts
index 2f9f263fc7975c..a4cdfa1c90d54e 100644
--- a/src/native/corehost/browserhost/host/host.ts
+++ b/src/native/corehost/browserhost/host/host.ts
@@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import type { CharPtr, CharPtrPtr, VfsAsset, VoidPtr, VoidPtrPtr } from "./types";
+import type { CharPtr, VfsAsset, VoidPtr, VoidPtrPtr } from "./types";
import { _ems_ } from "../../../libs/Common/JavaScript/ems-ambient";
const loadedAssemblies: Map = new Map();
@@ -90,57 +90,8 @@ export function installVfsFile(bytes: Uint8Array, asset: VfsAsset) {
);
}
-
-const HOST_PROPERTY_RUNTIME_CONTRACT = "HOST_RUNTIME_CONTRACT";
-const HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES = "TRUSTED_PLATFORM_ASSEMBLIES";
-const HOST_PROPERTY_ENTRY_ASSEMBLY_NAME = "ENTRY_ASSEMBLY_NAME";
-const HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES = "NATIVE_DLL_SEARCH_DIRECTORIES";
-const HOST_PROPERTY_APP_PATHS = "APP_PATHS";
-const APP_CONTEXT_BASE_DIRECTORY = "APP_CONTEXT_BASE_DIRECTORY";
-const RUNTIME_IDENTIFIER = "RUNTIME_IDENTIFIER";
-
export function initializeCoreCLR(): number {
- const loaderConfig = _ems_.dotnetApi.getConfig();
- const hostContractPtr = _ems_._BrowserHost_CreateHostContract();
- const runtimeConfigProperties = new Map();
- if (loaderConfig.runtimeConfig?.runtimeOptions?.configProperties) {
- for (const [key, value] of Object.entries(loaderConfig.runtimeConfig?.runtimeOptions?.configProperties)) {
- runtimeConfigProperties.set(key, "" + value);
- }
- }
- const assemblyPaths = loaderConfig.resources!.assembly.map(a => "/" + a.virtualPath);
- const coreAssemblyPaths = loaderConfig.resources!.coreAssembly.map(a => "/" + a.virtualPath);
- const tpa = [...coreAssemblyPaths, ...assemblyPaths].join(":");
- runtimeConfigProperties.set(HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES, tpa);
- runtimeConfigProperties.set(HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES, loaderConfig.virtualWorkingDirectory!);
- runtimeConfigProperties.set(HOST_PROPERTY_APP_PATHS, loaderConfig.virtualWorkingDirectory!);
- runtimeConfigProperties.set(HOST_PROPERTY_ENTRY_ASSEMBLY_NAME, loaderConfig.mainAssemblyName!);
- runtimeConfigProperties.set(APP_CONTEXT_BASE_DIRECTORY, "/");
- runtimeConfigProperties.set(RUNTIME_IDENTIFIER, "browser-wasm");
- runtimeConfigProperties.set(HOST_PROPERTY_RUNTIME_CONTRACT, `0x${(hostContractPtr as unknown as number).toString(16)}`);
-
- const buffers: VoidPtr[] = [];
- const appctx_keys = _ems_._malloc(4 * runtimeConfigProperties.size) as any as CharPtrPtr;
- const appctx_values = _ems_._malloc(4 * runtimeConfigProperties.size) as any as CharPtrPtr;
- buffers.push(appctx_keys as any);
- buffers.push(appctx_values as any);
-
- let propertyCount = 0;
- for (const [key, value] of runtimeConfigProperties.entries()) {
- const keyPtr = _ems_.dotnetBrowserUtilsExports.stringToUTF8Ptr(key);
- const valuePtr = _ems_.dotnetBrowserUtilsExports.stringToUTF8Ptr(value);
- _ems_.dotnetApi.setHeapU32((appctx_keys as any) + (propertyCount * 4), keyPtr);
- _ems_.dotnetApi.setHeapU32((appctx_values as any) + (propertyCount * 4), valuePtr);
- propertyCount++;
- buffers.push(keyPtr as any);
- buffers.push(valuePtr as any);
- }
-
- const res = _ems_._BrowserHost_InitializeCoreCLR(propertyCount, appctx_keys, appctx_values);
- for (const buf of buffers) {
- _ems_._free(buf as any);
- }
- return res;
+ return _ems_._BrowserHost_InitializeCoreCLR();
}
// bool BrowserHost_ExternalAssemblyProbe(const char* pathPtr, /*out*/ void **outDataStartPtr, /*out*/ int64_t* outSize);
diff --git a/src/native/corehost/browserhost/libBrowserHost.footer.js b/src/native/corehost/browserhost/libBrowserHost.footer.js
index a64f55ecc6975d..49504a4252d243 100644
--- a/src/native/corehost/browserhost/libBrowserHost.footer.js
+++ b/src/native/corehost/browserhost/libBrowserHost.footer.js
@@ -19,14 +19,10 @@
const exports = {};
libBrowserHost(exports);
- // libBrowserHostFn is too complex for acorn-optimizer.mjs to find the dependencies
- let explicitDeps = [
- "wasm_load_icu_data", "BrowserHost_CreateHostContract", "BrowserHost_InitializeCoreCLR", "BrowserHost_ExecuteAssembly"
- ];
let commonDeps = [
"$DOTNET", "$DOTNET_INTEROP", "$ENV", "$FS", "$NODEFS",
"$libBrowserHostFn",
- ...explicitDeps
+ "wasm_load_icu_data", "BrowserHost_InitializeCoreCLR", "BrowserHost_ExecuteAssembly"
];
const lib = {
$BROWSER_HOST: {
@@ -39,18 +35,28 @@
exports.dotnetInitializeModule(dotnetInternals);
BROWSER_HOST.assignExports(exports, BROWSER_HOST);
- const loaderConfig = dotnetInternals[2/*InternalExchangeIndex.LoaderConfig*/];
- if (!loaderConfig.resources.assembly ||
- !loaderConfig.resources.coreAssembly ||
- loaderConfig.resources.coreAssembly.length === 0 ||
- !loaderConfig.mainAssemblyName ||
- !loaderConfig.virtualWorkingDirectory ||
- !loaderConfig.environmentVariables) {
+ const HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES = "TRUSTED_PLATFORM_ASSEMBLIES";
+ const HOST_PROPERTY_ENTRY_ASSEMBLY_NAME = "ENTRY_ASSEMBLY_NAME";
+ const HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES = "NATIVE_DLL_SEARCH_DIRECTORIES";
+ const HOST_PROPERTY_APP_PATHS = "APP_PATHS";
+
+ const config = dotnetInternals[2/*InternalExchangeIndex.LoaderConfig*/];
+ if (!config.resources.assembly ||
+ !config.resources.coreAssembly ||
+ config.resources.coreAssembly.length === 0 ||
+ !config.mainAssemblyName ||
+ !config.virtualWorkingDirectory ||
+ !config.environmentVariables) {
throw new Error("Invalid runtime config, cannot initialize the runtime.");
}
-
- for (const key in loaderConfig.environmentVariables) {
- ENV[key] = loaderConfig.environmentVariables[key];
+ const assemblyPaths = config.resources.assembly.map(a => "/" + a.virtualPath);
+ const coreAssemblyPaths = config.resources.coreAssembly.map(a => "/" + a.virtualPath);
+ config.environmentVariables[HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES] = [...coreAssemblyPaths, ...assemblyPaths].join(":");
+ config.environmentVariables[HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES] = config.virtualWorkingDirectory;
+ config.environmentVariables[HOST_PROPERTY_APP_PATHS] = config.virtualWorkingDirectory;
+ config.environmentVariables[HOST_PROPERTY_ENTRY_ASSEMBLY_NAME] = config.mainAssemblyName;
+ for (const key in config.environmentVariables) {
+ ENV[key] = config.environmentVariables[key];
}
if (ENVIRONMENT_IS_NODE) {
@@ -62,6 +68,11 @@
}
}
},
+ // libBrowserHostFn is too complex for acorn-optimizer.mjs to find the dependencies
+ AJSDCE_Deps: function () {
+ _BrowserHost_InitializeCoreCLR();
+ _BrowserHost_ExecuteAssembly();
+ },
},
$libBrowserHostFn: libBrowserHost,
$BROWSER_HOST__postset: "BROWSER_HOST.selfInitialize()",
@@ -69,18 +80,13 @@
};
let assignExportsBuilder = "";
- let explicitImportsBuilder = "";
for (const exportName of Reflect.ownKeys(exports)) {
const name = String(exportName);
if (name === "dotnetInitializeModule") continue;
lib[name] = () => "dummy";
assignExportsBuilder += `_${String(name)} = exports.${String(name)};\n`;
}
- for (const importName of explicitDeps) {
- explicitImportsBuilder += `_${importName}();\n`;
- }
lib.$BROWSER_HOST.assignExports = new Function("exports", assignExportsBuilder);
- lib.$BROWSER_HOST.explicitImports = new Function(explicitImportsBuilder);
autoAddDeps(lib, "$BROWSER_HOST");
addToLibrary(lib);
diff --git a/src/native/corehost/browserhost/loader/assets.ts b/src/native/corehost/browserhost/loader/assets.ts
index 7edbcb151e9c20..186869196b16fa 100644
--- a/src/native/corehost/browserhost/loader/assets.ts
+++ b/src/native/corehost/browserhost/loader/assets.ts
@@ -7,7 +7,7 @@ import { dotnetAssert, dotnetLogger, dotnetInternals, dotnetBrowserHostExports,
import { ENVIRONMENT_IS_WEB, ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_NODE } from "./per-module";
import { createPromiseCompletionSource, delay } from "./promise-completion-source";
import { locateFile, makeURLAbsoluteWithApplicationBase } from "./bootstrap";
-import { fetchLike, responseLike } from "./polyfills";
+import { fetchLike } from "./polyfills";
import { loaderConfig } from "./config";
let throttlingPCS: PromiseCompletionSource | undefined;
@@ -39,7 +39,7 @@ export async function loadJSModule(asset: JsAsset): Promise {
}
assetInternal.behavior = "js-module-dotnet";
if (typeof loadBootResourceCallback === "function") {
- const type = behaviorToBlazorAssetTypeMap[assetInternal.behavior];
+ const type = runtimeToBlazorAssetTypeMap[assetInternal.behavior];
dotnetAssert.check(type, `Unsupported asset behavior: ${assetInternal.behavior}`);
const customLoadResult = loadBootResourceCallback(type, assetInternal.name, asset.resolvedUrl!, assetInternal.integrity!, assetInternal.behavior);
dotnetAssert.check(typeof customLoadResult === "string", "loadBootResourceCallback for JS modules must return string URL");
@@ -218,16 +218,18 @@ async function loadResourceRetry(asset: AssetEntryInternal): Promise {
try {
response = await loadResourceThrottle(asset);
if (!response) {
- response = responseLike(asset.resolvedUrl!, null, {
- status: 404,
+ response = {
+ ok: false,
+ status: -1,
statusText: "No response",
- });
+ } as any;
}
} catch (err: any) {
- response = responseLike(asset.resolvedUrl!, null, {
- status: 500,
+ response = {
+ ok: false,
+ status: -1,
statusText: err.message || "Exception during fetch",
- });
+ } as any;
}
return response;
}
@@ -262,24 +264,28 @@ async function loadResourceThrottle(asset: AssetEntryInternal): Promise {
- const expectedContentType = behaviorToContentTypeMap[asset.behavior];
- dotnetAssert.check(expectedContentType, `Unsupported asset behavior: ${asset.behavior}`);
if (asset.buffer) {
- const arrayBuffer = await asset.buffer;
- return responseLike(asset.resolvedUrl!, arrayBuffer, {
- status: 200,
- statusText: "OK",
+ return {
+ ok: true,
headers: {
- "Content-Length": arrayBuffer.byteLength.toString(),
- "Content-Type": expectedContentType,
+ length: 0,
+ get: () => null
+ },
+ url: asset.resolvedUrl,
+ arrayBuffer: () => Promise.resolve(asset.buffer!),
+ json: () => {
+ throw new Error("NotImplementedException");
+ },
+ text: () => {
+ throw new Error("NotImplementedException");
}
- });
+ };
}
if (asset.pendingDownload) {
return asset.pendingDownload.response;
}
if (typeof loadBootResourceCallback === "function") {
- const type = behaviorToBlazorAssetTypeMap[asset.behavior];
+ const type = runtimeToBlazorAssetTypeMap[asset.behavior];
dotnetAssert.check(type, `Unsupported asset behavior: ${asset.behavior}`);
const customLoadResult = loadBootResourceCallback(type, asset.name, asset.resolvedUrl!, asset.integrity!, asset.behavior);
if (typeof customLoadResult === "string") {
@@ -311,7 +317,7 @@ async function loadResourceFetch(asset: AssetEntryInternal): Promise {
}
}
- return fetchLike(asset.resolvedUrl!, fetchOptions, expectedContentType);
+ return fetchLike(asset.resolvedUrl!, fetchOptions);
}
function onDownloadedAsset() {
@@ -325,7 +331,7 @@ export function verifyAllAssetsDownloaded(): void {
dotnetAssert.check(downloadedAssetsCount === totalAssetsToDownload, `Not all assets were downloaded. Downloaded ${downloadedAssetsCount} out of ${totalAssetsToDownload}`);
}
-const behaviorToBlazorAssetTypeMap: { [key: string]: WebAssemblyBootResourceType | undefined } = {
+const runtimeToBlazorAssetTypeMap: { [key: string]: WebAssemblyBootResourceType | undefined } = {
"resource": "assembly",
"assembly": "assembly",
"pdb": "pdb",
@@ -338,13 +344,3 @@ const behaviorToBlazorAssetTypeMap: { [key: string]: WebAssemblyBootResourceType
"js-module-runtime": "dotnetjs",
"js-module-threads": "dotnetjs"
};
-
-const behaviorToContentTypeMap: { [key: string]: string | undefined } = {
- "resource": "application/octet-stream",
- "assembly": "application/octet-stream",
- "pdb": "application/octet-stream",
- "icu": "application/octet-stream",
- "vfs": "application/octet-stream",
- "manifest": "application/json",
- "dotnetwasm": "application/wasm",
-};
diff --git a/src/native/corehost/browserhost/loader/config.ts b/src/native/corehost/browserhost/loader/config.ts
index 5221562a2d5372..5a8421a1b1db6c 100644
--- a/src/native/corehost/browserhost/loader/config.ts
+++ b/src/native/corehost/browserhost/loader/config.ts
@@ -40,7 +40,6 @@ function mergeConfigs(target: LoaderConfigInternal, source: Partial {
return _nodeUrl;
}
-export async function fetchLike(url: string, init?: RequestInit, expectedContentType?: string): Promise {
+export async function fetchLike(url: string, init?: RequestInit): Promise {
try {
await nodeFs();
await nodeUrl();
@@ -85,66 +85,60 @@ export async function fetchLike(url: string, init?: RequestInit, expectedContent
}
const arrayBuffer = await _nodeFs.promises.readFile(url);
- return responseLike(url, arrayBuffer, {
- status: 200,
- statusText: "OK",
+ return {
+ ok: true,
headers: {
- "Content-Length": arrayBuffer.byteLength.toString(),
- "Content-Type": expectedContentType || "application/octet-stream"
+ length: 0,
+ get: () => null
+ },
+ url,
+ arrayBuffer: () => arrayBuffer,
+ json: () => {
+ throw new Error("NotImplementedException");
+ },
+ text: () => {
+ throw new Error("NotImplementedException");
}
- });
+ };
} else if (hasFetch) {
return globalThis.fetch(url, init || { credentials: "same-origin" });
} else if (typeof (read) === "function") {
- const arrayBuffer = read(url, "binary");
- return responseLike(url, arrayBuffer, {
- status: 200,
- statusText: "OK",
+ return {
+ ok: true,
+ url,
headers: {
- "Content-Length": arrayBuffer.byteLength.toString(),
- "Content-Type": expectedContentType || "application/octet-stream"
- }
- });
+ length: 0,
+ get: () => null
+ },
+ arrayBuffer: () => {
+ return new Uint8Array(read(url, "binary"));
+ },
+ json: () => {
+ return JSON.parse(read(url, "utf8"));
+ },
+ text: () => read(url, "utf8")
+ };
}
} catch (e: any) {
- return responseLike(url, null, {
+ return {
+ ok: false,
+ url,
status: 500,
+ headers: {
+ length: 0,
+ get: () => null
+ },
statusText: "ERR28: " + e,
- headers: {},
- });
- }
- throw new Error("No fetch implementation available");
-}
-
-export function responseLike(url: string, body: ArrayBuffer | null, options: ResponseInit): Response {
- if (typeof globalThis.Response === "function") {
- const response = new Response(body, options);
-
- // Best-effort alignment with the fallback object shape:
- // only define `url` if it does not already exist on the response.
- if (typeof (response as any).url === "undefined") {
- try {
- Object.defineProperty(response, "url", { value: url });
- } catch {
- // Ignore if the implementation does not allow redefining `url`
+ arrayBuffer: () => {
+ throw e;
+ },
+ json: () => {
+ throw e;
+ },
+ text: () => {
+ throw e;
}
- }
-
- return response;
+ };
}
- return {
- ok: body !== null && options.status === 200,
- headers: {
- ...options.headers,
- get: (name: string) => (options.headers as any)[name] || null
- },
- url,
- arrayBuffer: () => Promise.resolve(body),
- json: () => {
- throw new Error("NotImplementedException");
- },
- text: () => {
- throw new Error("NotImplementedException");
- }
- };
+ throw new Error("No fetch implementation available");
}
diff --git a/src/native/libs/Common/JavaScript/types/ems-ambient.ts b/src/native/libs/Common/JavaScript/types/ems-ambient.ts
index e4ff4f2a05a637..29d9eb66590ffb 100644
--- a/src/native/libs/Common/JavaScript/types/ems-ambient.ts
+++ b/src/native/libs/Common/JavaScript/types/ems-ambient.ts
@@ -6,7 +6,7 @@ import type {
EmscriptenModuleInternal, InternalExchange, InternalExchangeSubscriber,
RuntimeAPI, LoaderExports, BrowserUtilsExports, RuntimeExports,
VoidPtr, JSMarshalerArguments, CSFnHandle, TypedArray,
- MemOffset, CharPtrPtr
+ MemOffset
} from "../types";
// we want to use the cross-module symbols defined in closure of dotnet.native.js
@@ -27,8 +27,7 @@ export type EmsAmbientSymbolsType = EmscriptenModuleInternal & {
_GetDotNetRuntimeContractDescriptor: () => void;
_SystemJS_ExecuteTimerCallback: () => void;
_SystemJS_ExecuteBackgroundJobCallback: () => void;
- _BrowserHost_CreateHostContract: () => VoidPtr;
- _BrowserHost_InitializeCoreCLR: (propertiesCount: number, propertyKeys: CharPtrPtr, propertyValues: CharPtrPtr) => number;
+ _BrowserHost_InitializeCoreCLR: () => number;
_BrowserHost_ExecuteAssembly: (mainAssemblyNamePtr: number, argsLength: number, argsPtr: number) => number;
_wasm_load_icu_data: (dataPtr: VoidPtr) => number;
_SystemInteropJS_GetManagedStackTrace: (args: JSMarshalerArguments) => void;
diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c
index 7d2acc37e8af07..d5121676bbf642 100644
--- a/src/native/libs/System.Native/entrypoints.c
+++ b/src/native/libs/System.Native/entrypoints.c
@@ -121,8 +121,7 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_LChflagsCanSetHiddenFlag)
DllImportEntry(SystemNative_FChflags)
DllImportEntry(SystemNative_CanGetHiddenFlag)
- DllImportEntry(SystemNative_ReadThreadInfo)
- DllImportEntry(SystemNative_ReadProcessInfo)
+ DllImportEntry(SystemNative_ReadProcessStatusInfo)
DllImportEntry(SystemNative_Log)
DllImportEntry(SystemNative_LogError)
DllImportEntry(SystemNative_AlignedAlloc)
diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c
index 4e1587be8e4f0b..f7af86614ded42 100644
--- a/src/native/libs/System.Native/pal_io.c
+++ b/src/native/libs/System.Native/pal_io.c
@@ -1849,97 +1849,31 @@ int32_t SystemNative_CanGetHiddenFlag(void)
#endif
}
-int32_t SystemNative_ReadThreadInfo(int32_t pid, int32_t tid, ThreadInfo* threadInfo)
+int32_t SystemNative_ReadProcessStatusInfo(pid_t pid, ProcessStatus* processStatus)
{
#ifdef __sun
- char infoFilename[64];
- snprintf(infoFilename, sizeof(infoFilename), "/proc/%d/lwp/%d/lwpsinfo", pid, tid);
+ char statusFilename[64];
+ snprintf(statusFilename, sizeof(statusFilename), "/proc/%d/psinfo", pid);
intptr_t fd;
- while ((fd = open(infoFilename, O_RDONLY)) < 0 && errno == EINTR);
+ while ((fd = open(statusFilename, O_RDONLY)) < 0 && errno == EINTR);
if (fd < 0)
{
return 0;
}
- lwpsinfo_t pr;
- int result = Common_Read(fd, &pr, sizeof(pr));
+ psinfo_t status;
+ int result = Common_Read(fd, &status, sizeof(psinfo_t));
close(fd);
- if (result < sizeof (pr))
+ if (result >= 0)
{
- errno = EIO;
- return -1;
- }
-
- threadInfo->Tid = pr.pr_lwpid;
- threadInfo->Priority = pr.pr_pri;
- threadInfo->NiceVal = pr.pr_nice;
- // Status code, a char: ...
- threadInfo->StatusCode = (uchar_t)pr.pr_sname;
- // Thread start time and CPU time
- threadInfo->StartTime = pr.pr_start.tv_sec;
- threadInfo->StartTimeNsec = pr.pr_start.tv_nsec;
- threadInfo->CpuTotalTime = pr.pr_time.tv_sec;
- threadInfo->CpuTotalTimeNsec = pr.pr_time.tv_nsec;
-
- return 0;
-#else
- (void)pid, (void)tid, (void)threadInfo;
- errno = ENOTSUP;
- return -1;
-#endif // __sun
-}
-
-// The struct passing is limited, so the args string is handled separately here.
-int32_t SystemNative_ReadProcessInfo(int32_t pid, ProcessInfo* processInfo, uint8_t *argBuf, int32_t argBufSize)
-{
-#ifdef __sun
- if (argBufSize != 0 && argBufSize < PRARGSZ)
- {
- errno = EINVAL;
- return -1;
- }
-
- char infoFilename[64];
- snprintf(infoFilename, sizeof(infoFilename), "/proc/%d/psinfo", pid);
-
- intptr_t fd;
- while ((fd = open(infoFilename, O_RDONLY)) < 0 && errno == EINTR);
- if (fd < 0)
- {
- return 0;
- }
-
- psinfo_t pr;
- int result = Common_Read(fd, &pr, sizeof(pr));
- close(fd);
- if (result < sizeof (pr))
- {
- errno = EIO;
- return -1;
- }
-
- processInfo->Pid = pr.pr_pid;
- processInfo->ParentPid = pr.pr_ppid;
- processInfo->SessionId = pr.pr_sid;
- processInfo->Priority = pr.pr_lwp.pr_pri;
- processInfo->NiceVal = pr.pr_lwp.pr_nice;
- // pr_size and pr_rsize are in Kbytes.
- processInfo->VirtualSize = (uint64_t)pr.pr_size * 1024;
- processInfo->ResidentSetSize = (uint64_t)pr.pr_rssize * 1024;
- processInfo->StartTime = pr.pr_start.tv_sec;
- processInfo->StartTimeNsec = pr.pr_start.tv_nsec;
- processInfo->CpuTotalTime = pr.pr_time.tv_sec;
- processInfo->CpuTotalTimeNsec = pr.pr_time.tv_nsec;
-
- if (argBuf != NULL && argBufSize != 0)
- {
- SafeStringCopy((char*)argBuf, PRARGSZ, pr.pr_psargs);
+ processStatus->ResidentSetSize = status.pr_rssize * 1024; // pr_rssize is in Kbytes
+ return 1;
}
return 0;
#else
- (void)pid, (void)processInfo, (void)argBuf, (void)argBufSize;
+ (void)pid, (void)processStatus;
errno = ENOTSUP;
return -1;
#endif // __sun
diff --git a/src/native/libs/System.Native/pal_io.h b/src/native/libs/System.Native/pal_io.h
index 2517e5d6297d8b..330fa2997b9f20 100644
--- a/src/native/libs/System.Native/pal_io.h
+++ b/src/native/libs/System.Native/pal_io.h
@@ -38,32 +38,9 @@ typedef struct
typedef struct
{
- // note: sorted by size to avoid alignment padding
- uint64_t VirtualSize;
- uint64_t ResidentSetSize;
- int64_t StartTime; // time proc. started
- int64_t StartTimeNsec;
- int64_t CpuTotalTime; // Cumulative CPU time (user+sys)
- int64_t CpuTotalTimeNsec;
- int32_t Pid;
- int32_t ParentPid;
- int32_t SessionId;
- int32_t Priority;
- int32_t NiceVal;
-} ProcessInfo;
-
-typedef struct
-{
- // note: sorted by size to avoid alignment padding
- int64_t StartTime; // time thread started
- int64_t StartTimeNsec;
- int64_t CpuTotalTime; // cumulative CPU time (user+sys)
- int64_t CpuTotalTimeNsec;
- int32_t Tid;
- int32_t Priority;
- int32_t NiceVal;
- uint16_t StatusCode; // See ProcFsStateToThreadState()
-} ThreadInfo;
+ size_t ResidentSetSize;
+ // add more fields when needed.
+} ProcessStatus;
// NOTE: the layout of this type is intended to exactly match the layout of a `struct iovec`. There are
// assertions in pal_networking.c that validate this.
@@ -828,18 +805,11 @@ PALEXPORT int32_t SystemNative_LChflagsCanSetHiddenFlag(void);
PALEXPORT int32_t SystemNative_CanGetHiddenFlag(void);
/**
- * Reads the lwpsinfo_t struct and converts into ThreadInfo.
+ * Reads the psinfo_t struct and converts into ProcessStatus.
*
- * Returns 0 on success; otherwise, returns -1 and sets errno.
- */
-PALEXPORT int32_t SystemNative_ReadThreadInfo(int32_t pid, int32_t tid, ThreadInfo* threadInfo);
-
-/**
- * Reads the psinfo_t struct and converts into ProcessInfo.
- *
- * Returns 0 on success; otherwise, returns -1 and sets errno.
+ * Returns 1 if the process status was read; otherwise, 0.
*/
-PALEXPORT int32_t SystemNative_ReadProcessInfo(int32_t pid, ProcessInfo* processInfo, uint8_t *argBuf, int32_t argBufSize);
+PALEXPORT int32_t SystemNative_ReadProcessStatusInfo(pid_t pid, ProcessStatus* processStatus);
/**
* Reads the number of bytes specified into the provided buffer from the specified, opened file descriptor at specified offset.
diff --git a/src/native/libs/System.Native/pal_process.c b/src/native/libs/System.Native/pal_process.c
index 845c4ed3293622..129fd612e33168 100644
--- a/src/native/libs/System.Native/pal_process.c
+++ b/src/native/libs/System.Native/pal_process.c
@@ -553,9 +553,6 @@ static int32_t ConvertRLimitResourcesPalToPlatform(RLimitResources value)
#ifdef RLIMIT_RSS
case PAL_RLIMIT_RSS:
return RLIMIT_RSS;
-#elif defined(RLIMIT_VMEM)
- case PAL_RLIMIT_RSS:
- return RLIMIT_VMEM;
#endif
#ifdef RLIMIT_MEMLOCK
case PAL_RLIMIT_MEMLOCK:
diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ecc.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ecc.c
index 88c4832ef30736..dc5f195ab24226 100644
--- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ecc.c
+++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ecc.c
@@ -24,7 +24,10 @@ int32_t AppleCryptoNative_EccGenerateKey(int32_t keySizeBits,
{
CFDictionaryAddValue(attributes, kSecAttrKeyType, kSecAttrKeyTypeEC);
CFDictionaryAddValue(attributes, kSecAttrKeySizeInBits, cfKeySizeValue);
- CFDictionaryAddValue(attributes, kSecUseDataProtectionKeychain, kCFBooleanTrue);
+ if (__builtin_available(macOS 10.15, iOS 13, tvOS 13, *))
+ {
+ CFDictionaryAddValue(attributes, kSecUseDataProtectionKeychain, kCFBooleanTrue);
+ }
*pPrivateKey = SecKeyCreateRandomKey(attributes, pErrorOut);
if (*pPrivateKey != NULL)
diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_rsa.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_rsa.c
index fa76a4323225e5..1746828d5b0d7d 100644
--- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_rsa.c
+++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_rsa.c
@@ -26,7 +26,10 @@ int32_t AppleCryptoNative_RsaGenerateKey(int32_t keySizeBits,
{
CFDictionaryAddValue(attributes, kSecAttrKeyType, kSecAttrKeyTypeRSA);
CFDictionaryAddValue(attributes, kSecAttrKeySizeInBits, cfKeySizeValue);
- CFDictionaryAddValue(attributes, kSecUseDataProtectionKeychain, kCFBooleanTrue);
+ if (__builtin_available(macOS 10.15, iOS 13, tvOS 13, *))
+ {
+ CFDictionaryAddValue(attributes, kSecUseDataProtectionKeychain, kCFBooleanTrue);
+ }
*pPrivateKey = SecKeyCreateRandomKey(attributes, pErrorOut);
if (*pPrivateKey != NULL)
diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_sec.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_sec.c
index 8e48ff2ea279a5..07cc20d1724f20 100644
--- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_sec.c
+++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_sec.c
@@ -5,5 +5,10 @@
CFStringRef AppleCryptoNative_SecCopyErrorMessageString(OSStatus osStatus)
{
- return SecCopyErrorMessageString(osStatus, NULL);
+ if (__builtin_available(iOS 11.3, tvOS 11.3, *))
+ {
+ return SecCopyErrorMessageString(osStatus, NULL);
+ }
+
+ return CFStringCreateWithFormat(NULL, NULL, CFSTR("OSStatus %d"), (int)osStatus);
}
diff --git a/src/native/minipal/memorybarrierprocesswide.c b/src/native/minipal/memorybarrierprocesswide.c
index 6a9704c9920a98..7582332f86c9e9 100644
--- a/src/native/minipal/memorybarrierprocesswide.c
+++ b/src/native/minipal/memorybarrierprocesswide.c
@@ -166,9 +166,27 @@ void minipal_memory_barrier_process_wide(void)
// Iterate through each of the threads in the list.
for (mach_msg_type_number_t i = 0; i < cThreads; i++)
{
- // Request the threads pointer values to force the thread to emit a memory barrier
- size_t registers = 128;
- machret = thread_get_register_pointer_values(pThreads[i], &sp, ®isters, registerValues);
+ if (__builtin_available (macOS 10.14, iOS 12, tvOS 9, *))
+ {
+ // Request the threads pointer values to force the thread to emit a memory barrier
+ size_t registers = 128;
+ machret = thread_get_register_pointer_values(pThreads[i], &sp, ®isters, registerValues);
+ }
+ else
+ {
+ // fallback implementation for older OS versions
+#if defined(HOST_AMD64)
+ x86_thread_state64_t threadState;
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+ machret = thread_get_state(pThreads[i], x86_THREAD_STATE64, (thread_state_t)&threadState, &count);
+#elif defined(HOST_ARM64)
+ arm_thread_state64_t threadState;
+ mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT;
+ machret = thread_get_state(pThreads[i], ARM_THREAD_STATE64, (thread_state_t)&threadState, &count);
+#else
+ #error Unexpected architecture
+#endif
+ }
if (machret == KERN_INSUFFICIENT_BUFFER_SIZE)
{
diff --git a/src/native/package.json b/src/native/package.json
index a21651a2457791..5f4d6f1f0cfbd5 100644
--- a/src/native/package.json
+++ b/src/native/package.json
@@ -12,8 +12,8 @@
"scripts": {
"rollup:stub": "node rollup.stub.js",
"rollup:cmake": "rollup -c --environment ",
- "rollup:release": "rollup -c --environment Configuration:Release,ProductVersion:11.0,ContinuousIntegrationBuild:false",
- "rollup:debug": "rollup -c --environment Configuration:Debug,ProductVersion:11.0,ContinuousIntegrationBuild:false",
+ "rollup:release": "rollup -c --environment Configuration:Release,ProductVersion:11.0.0-dev,ContinuousIntegrationBuild:false",
+ "rollup:debug": "rollup -c --environment Configuration:Debug,ProductVersion:11.0.0-dev,ContinuousIntegrationBuild:false",
"lint": "eslint --no-color --max-warnings=0 \"./**/*.ts\" \"./**/*.js\"",
"format": "eslint --fix \"./**/*.ts\" \"./*.js\""
},
diff --git a/src/native/rollup.config.defines.js b/src/native/rollup.config.defines.js
index 675e964c570058..af36b8eb99be63 100644
--- a/src/native/rollup.config.defines.js
+++ b/src/native/rollup.config.defines.js
@@ -18,7 +18,7 @@ if (process.env.ProductVersion === undefined) {
export const configuration = process.env.Configuration !== "Release" && process.env.Configuration !== "RELEASE" ? "Debug" : "Release";
export const productVersion = process.env.ProductVersion;
export const isContinuousIntegrationBuild = process.env.ContinuousIntegrationBuild === "true" ? true : false;
-export const staticLibDestination = process.env.StaticLibDestination || `../../artifacts/obj/native/net${productVersion}-browser-${configuration}-wasm/lib`;
+export const staticLibDestination = process.env.StaticLibDestination || "../../artifacts/bin/browser-wasm.Debug/corehost";
console.log(`Rollup configuration: Configuration=${configuration}, ProductVersion=${productVersion}, ContinuousIntegrationBuild=${isContinuousIntegrationBuild}`);
From 530ab7b3792f305dcaecb1cbc5b0f047556d4172 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 19 Jan 2026 20:05:19 +0000
Subject: [PATCH 7/7] Change BFloat16.TrailingSignificand to return byte and
update ILogB formula
- Changed TrailingSignificand property from ushort to byte
- Changed ExtractTrailingSignificandFromBits to return byte
- Changed MinTrailingSignificand and MaxTrailingSignificand constants to byte
- Updated IsPow2 to use byte.PopCount
- Updated ILogB to use byte.LeadingZeroCount with adjusted formula
Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
---
.../src/System/Numerics/BFloat16.cs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
index 2d543808fd031a..545b9a62091637 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs
@@ -48,8 +48,8 @@ public readonly struct BFloat16
internal const sbyte MinExponent = -126;
internal const sbyte MaxExponent = +127;
- internal const ushort MinTrailingSignificand = 0x0000;
- internal const ushort MaxTrailingSignificand = 0x007F;
+ internal const byte MinTrailingSignificand = 0x00;
+ internal const byte MaxTrailingSignificand = 0x7F;
internal const int TrailingSignificandLength = 7;
internal const int SignificandLength = TrailingSignificandLength + 1;
@@ -124,7 +124,7 @@ internal byte Significand
}
}
- internal ushort TrailingSignificand
+ internal byte TrailingSignificand
{
get
{
@@ -138,9 +138,9 @@ internal static byte ExtractBiasedExponentFromBits(ushort bits)
return (byte)((bits >> BiasedExponentShift) & ShiftedBiasedExponentMask);
}
- internal static ushort ExtractTrailingSignificandFromBits(ushort bits)
+ internal static byte ExtractTrailingSignificandFromBits(ushort bits)
{
- return (ushort)(bits & TrailingSignificandMask);
+ return (byte)(bits & TrailingSignificandMask);
}
// INumberBase
@@ -877,12 +877,12 @@ public static bool IsPow2(BFloat16 value)
}
byte biasedExponent = ExtractBiasedExponentFromBits(bits);
- ushort trailingSignificand = ExtractTrailingSignificandFromBits(bits);
+ byte trailingSignificand = ExtractTrailingSignificandFromBits(bits);
if (biasedExponent == MinBiasedExponent)
{
// Subnormal values have 1 bit set when they're powers of 2
- return ushort.PopCount(trailingSignificand) == 1;
+ return byte.PopCount(trailingSignificand) == 1;
}
else if (biasedExponent == MaxBiasedExponent)
{
@@ -1191,7 +1191,7 @@ public static int ILogB(BFloat16 x)
}
Debug.Assert(IsSubnormal(x));
- return MinExponent - (ushort.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);
+ return MinExponent - byte.LeadingZeroCount(x.TrailingSignificand);
}
return x.Exponent;