diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 5b5d22984f53f8..479196edabbaca 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -48,13 +48,13 @@
https://github.com/dotnet/command-line-api
5618b2d243ccdeb5c7e50a298b33b13036b4351b
-
+
https://github.com/dotnet/emsdk
- 76e6b338e87093ddc9b3b650f027706aba65d388
+ 6625add9a3eadc2954af0311be35290cfefcddb0
-
+
https://github.com/dotnet/emsdk
- 76e6b338e87093ddc9b3b650f027706aba65d388
+ 6625add9a3eadc2954af0311be35290cfefcddb0
diff --git a/eng/Versions.props b/eng/Versions.props
index bb3c6456d69106..f5469fd5a4f3d4 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -22,8 +22,8 @@
false
$(AssemblyVersion)
true
- 7.0.0-rc.2.22459.3
- 7.0.0-rc.2.22459.3
+ 7.0.0-rc.2.22465.1
+ 7.0.0-rc.2.22465.1
1.1.2-beta1.22403.2
- 7.0.0-preview-20220914.1
+ 7.0.0-preview-20220916.1
7.0.100-1.22423.4
$(MicrosoftNETILLinkTasksVersion)
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index ca02a670d2142c..63253997dfc422 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -193,10 +193,10 @@ jobs:
# WebAssembly Firefox
- ${{ if eq(parameters.platform, 'Browser_wasm_firefox') }}:
- - (Ubuntu.1804.Amd64)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-webassembly-20220504035734-67908a0
+ - (Ubuntu.1804.Amd64)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-webassembly-20220908122752-67908a0
# WebAssembly windows
- ${{ if eq(parameters.platform, 'Browser_wasm_win') }}:
- - (Windows.Amd64.Server2022.Open)windows.amd64.server2022.open@mcr.microsoft.com/dotnet-buildtools/prereqs:windowsservercore-ltsc2022-helix-webassembly-20220620175048-bf70060
+ - (Windows.Amd64.Server2022.Open)windows.amd64.server2022.open@mcr.microsoft.com/dotnet-buildtools/prereqs:windowsservercore-ltsc2022-helix-webassembly-20220908122953-3a6fb49
${{ insert }}: ${{ parameters.jobParameters }}
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 3b7c12f25ccb12..1f9015cf8760e4 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -18631,10 +18631,45 @@ bool GenTree::isCommutativeHWIntrinsic() const
assert(gtOper == GT_HWINTRINSIC);
#ifdef TARGET_XARCH
- return HWIntrinsicInfo::IsCommutative(AsHWIntrinsic()->GetHWIntrinsicId());
-#else
- return false;
+ const GenTreeHWIntrinsic* node = AsHWIntrinsic();
+ NamedIntrinsic id = node->GetHWIntrinsicId();
+
+ if (HWIntrinsicInfo::IsCommutative(id))
+ {
+ return true;
+ }
+
+ if (HWIntrinsicInfo::IsMaybeCommutative(id))
+ {
+ switch (id)
+ {
+ case NI_SSE_Max:
+ case NI_SSE_Min:
+ {
+ return false;
+ }
+
+ case NI_SSE2_Max:
+ case NI_SSE2_Min:
+ {
+ return !varTypeIsFloating(node->GetSimdBaseType());
+ }
+
+ case NI_AVX_Max:
+ case NI_AVX_Min:
+ {
+ return false;
+ }
+
+ default:
+ {
+ unreached();
+ }
+ }
+ }
#endif // TARGET_XARCH
+
+ return false;
}
bool GenTree::isContainableHWIntrinsic() const
diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h
index 88e5b4ae575059..b1299df1c1f1cf 100644
--- a/src/coreclr/jit/hwintrinsic.h
+++ b/src/coreclr/jit/hwintrinsic.h
@@ -153,6 +153,11 @@ enum HWIntrinsicFlag : unsigned int
// the intrinsic can be used on hardware with AVX but not AVX2 support
HW_Flag_AvxOnlyCompatible = 0x40000,
+ // MaybeCommutative
+ // - if a binary-op intrinsic is maybe commutative (e.g., Max or Min for float/double), its op1 can possibly be
+ // contained
+ HW_Flag_MaybeCommutative = 0x80000,
+
#elif defined(TARGET_ARM64)
// The intrinsic has an immediate operand
// - the value can be (and should be) encoded in a corresponding instruction when the operand value is constant
@@ -626,6 +631,18 @@ struct HWIntrinsicInfo
return (flags & HW_Flag_Commutative) != 0;
}
+ static bool IsMaybeCommutative(NamedIntrinsic id)
+ {
+ HWIntrinsicFlag flags = lookupFlags(id);
+#if defined(TARGET_XARCH)
+ return (flags & HW_Flag_MaybeCommutative) != 0;
+#elif defined(TARGET_ARM64)
+ return false;
+#else
+#error Unsupported platform
+#endif
+ }
+
static bool RequiresCodegen(NamedIntrinsic id)
{
HWIntrinsicFlag flags = lookupFlags(id);
diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h
index 7068e39bd1b560..0fff3a98d3bec3 100644
--- a/src/coreclr/jit/hwintrinsiclistxarch.h
+++ b/src/coreclr/jit/hwintrinsiclistxarch.h
@@ -290,9 +290,9 @@ HARDWARE_INTRINSIC(SSE, LoadHigh,
HARDWARE_INTRINSIC(SSE, LoadLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(SSE, LoadScalarVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(SSE, LoadVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
-HARDWARE_INTRINSIC(SSE, Max, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative)
+HARDWARE_INTRINSIC(SSE, Max, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MaybeCommutative)
HARDWARE_INTRINSIC(SSE, MaxScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits)
-HARDWARE_INTRINSIC(SSE, Min, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative)
+HARDWARE_INTRINSIC(SSE, Min, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MaybeCommutative)
HARDWARE_INTRINSIC(SSE, MinScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits)
HARDWARE_INTRINSIC(SSE, MoveHighToLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhlps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment)
HARDWARE_INTRINSIC(SSE, MoveLowToHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment)
@@ -403,10 +403,10 @@ HARDWARE_INTRINSIC(SSE2, LoadLow,
HARDWARE_INTRINSIC(SSE2, LoadScalarVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(SSE2, LoadVector128, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(SSE2, MaskMove, 16, 3, {INS_maskmovdqu, INS_maskmovdqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg)
-HARDWARE_INTRINSIC(SSE2, Max, 16, 2, {INS_invalid, INS_pmaxub, INS_pmaxsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative)
+HARDWARE_INTRINSIC(SSE2, Max, 16, 2, {INS_invalid, INS_pmaxub, INS_pmaxsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_MaybeCommutative)
HARDWARE_INTRINSIC(SSE2, MemoryFence, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(SSE2, MaxScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits)
-HARDWARE_INTRINSIC(SSE2, Min, 16, 2, {INS_invalid, INS_pminub, INS_pminsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative)
+HARDWARE_INTRINSIC(SSE2, Min, 16, 2, {INS_invalid, INS_pminub, INS_pminsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_MaybeCommutative)
HARDWARE_INTRINSIC(SSE2, MinScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits)
HARDWARE_INTRINSIC(SSE2, MoveMask, 16, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg)
HARDWARE_INTRINSIC(SSE2, MoveScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_NoContainment)
@@ -598,8 +598,8 @@ HARDWARE_INTRINSIC(AVX, InsertVector128,
HARDWARE_INTRINSIC(AVX, LoadAlignedVector256, 32, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(AVX, LoadDquVector256, 32, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(AVX, LoadVector256, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics)
-HARDWARE_INTRINSIC(AVX, Max, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative)
-HARDWARE_INTRINSIC(AVX, Min, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative)
+HARDWARE_INTRINSIC(AVX, Max, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_MaybeCommutative)
+HARDWARE_INTRINSIC(AVX, Min, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_MaybeCommutative)
HARDWARE_INTRINSIC(AVX, MaskLoad, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps, INS_vmaskmovpd}, HW_Category_MemoryLoad, HW_Flag_NoFlag)
HARDWARE_INTRINSIC(AVX, MaskStore, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps, INS_vmaskmovpd}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_BaseTypeFromSecondArg)
HARDWARE_INTRINSIC(AVX, MoveMask, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
index d3e4ec30779124..51e42b8676b774 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
@@ -953,7 +953,8 @@ private static TypeDesc GetActualTemplateTypeForType(NodeFactory factory, TypeDe
private ISymbolNode GetStaticsNode(NodeFactory context, out BagElementKind staticsBagKind)
{
- ISymbolNode symbol = context.GCStaticEEType(GCPointerMap.FromStaticLayout(_type.GetClosestDefType()));
+ DefType closestCanonDefType = (DefType)_type.GetClosestDefType().ConvertToCanonForm(CanonicalFormKind.Specific);
+ ISymbolNode symbol = context.GCStaticEEType(GCPointerMap.FromStaticLayout(closestCanonDefType));
staticsBagKind = BagElementKind.GcStaticDesc;
return symbol;
@@ -961,7 +962,8 @@ private ISymbolNode GetStaticsNode(NodeFactory context, out BagElementKind stati
private ISymbolNode GetThreadStaticsNode(NodeFactory context, out BagElementKind staticsBagKind)
{
- ISymbolNode symbol = context.GCStaticEEType(GCPointerMap.FromThreadStaticLayout(_type.GetClosestDefType()));
+ DefType closestCanonDefType = (DefType)_type.GetClosestDefType().ConvertToCanonForm(CanonicalFormKind.Specific);
+ ISymbolNode symbol = context.GCStaticEEType(GCPointerMap.FromThreadStaticLayout(closestCanonDefType));
staticsBagKind = BagElementKind.ThreadStaticDesc;
return symbol;
@@ -997,13 +999,14 @@ public override IEnumerable GetStaticDependencies(NodeFacto
if (!_isUniversalCanon)
{
- if (_type.GetClosestDefType().GCStaticFieldSize.AsInt > 0)
+ DefType closestCanonDefType = (DefType)_type.GetClosestDefType().ConvertToCanonForm(CanonicalFormKind.Specific);
+ if (closestCanonDefType.GCStaticFieldSize.AsInt > 0)
{
BagElementKind ignored;
yield return new DependencyListEntry(GetStaticsNode(context, out ignored), "type gc static info");
}
- if (_type.GetClosestDefType().ThreadGcStaticFieldSize.AsInt > 0)
+ if (closestCanonDefType.ThreadGcStaticFieldSize.AsInt > 0)
{
BagElementKind ignored;
yield return new DependencyListEntry(GetThreadStaticsNode(context, out ignored), "type thread static info");
@@ -1207,24 +1210,24 @@ public override Vertex WriteVertex(NodeFactory factory)
if (!_isUniversalCanon)
{
- DefType closestDefType = _type.GetClosestDefType();
- if (closestDefType.NonGCStaticFieldSize.AsInt != 0)
+ DefType closestCanonDefType = (DefType)_type.GetClosestDefType().ConvertToCanonForm(CanonicalFormKind.Specific);
+ if (closestCanonDefType.NonGCStaticFieldSize.AsInt != 0)
{
- layoutInfo.AppendUnsigned(BagElementKind.NonGcStaticDataSize, checked((uint)closestDefType.NonGCStaticFieldSize.AsInt));
+ layoutInfo.AppendUnsigned(BagElementKind.NonGcStaticDataSize, checked((uint)closestCanonDefType.NonGCStaticFieldSize.AsInt));
}
- if (closestDefType.GCStaticFieldSize.AsInt != 0)
+ if (closestCanonDefType.GCStaticFieldSize.AsInt != 0)
{
- layoutInfo.AppendUnsigned(BagElementKind.GcStaticDataSize, checked((uint)closestDefType.GCStaticFieldSize.AsInt));
+ layoutInfo.AppendUnsigned(BagElementKind.GcStaticDataSize, checked((uint)closestCanonDefType.GCStaticFieldSize.AsInt));
BagElementKind staticDescBagType;
ISymbolNode staticsDescSymbol = GetStaticsNode(factory, out staticDescBagType);
uint gcStaticsSymbolIndex = factory.MetadataManager.NativeLayoutInfo.StaticsReferences.GetIndex(staticsDescSymbol);
layoutInfo.AppendUnsigned(staticDescBagType, gcStaticsSymbolIndex);
}
- if (closestDefType.ThreadGcStaticFieldSize.AsInt != 0)
+ if (closestCanonDefType.ThreadGcStaticFieldSize.AsInt != 0)
{
- layoutInfo.AppendUnsigned(BagElementKind.ThreadStaticDataSize, checked((uint)closestDefType.ThreadGcStaticFieldSize.AsInt));
+ layoutInfo.AppendUnsigned(BagElementKind.ThreadStaticDataSize, checked((uint)closestCanonDefType.ThreadGcStaticFieldSize.AsInt));
BagElementKind threadStaticDescBagType;
ISymbolNode threadStaticsDescSymbol = GetThreadStaticsNode(factory, out threadStaticDescBagType);
uint threadStaticsSymbolIndex = factory.MetadataManager.NativeLayoutInfo.StaticsReferences.GetIndex(threadStaticsDescSymbol);
diff --git a/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs b/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs
index 3c3e831fac98d4..a9ebcba2950c55 100644
--- a/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs
@@ -50,7 +50,9 @@ public Native(WAVEOUTCAPS managed)
wMid = managed.wMid;
wPid = managed.wPid;
vDriverVersion = managed.vDriverVersion;
- managed.szPname.CopyTo(MemoryMarshal.CreateSpan(ref szPname[0], szPnameLength));
+ Span szPnameSpan = MemoryMarshal.CreateSpan(ref szPname[0], szPnameLength);
+ szPnameSpan.Clear();
+ managed.szPname?.CopyTo(szPnameSpan);
dwFormats = managed.dwFormats;
wChannels = managed.wChannels;
wReserved1 = managed.wReserved1;
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
index a26b2fe68e7190..e36ae28fd4316d 100644
--- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
+++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
@@ -299,43 +299,45 @@ private static void BindInstance(
if (config != null && config.GetChildren().Any())
{
- // for arrays, collections, and read-only list-like interfaces, we concatenate on to what is already there
+ // for arrays, collections, and read-only list-like interfaces, we concatenate on to what is already there, if we can
if (type.IsArray || IsArrayCompatibleInterface(type))
{
if (!bindingPoint.IsReadOnly)
{
bindingPoint.SetValue(BindArray(type, (IEnumerable?)bindingPoint.Value, config, options));
+ return;
+ }
+
+ // for getter-only collection properties that we can't add to, nothing more we can do
+ if (type.IsArray || IsImmutableArrayCompatibleInterface(type))
+ {
+ return;
}
- return;
}
- // for sets and read-only set interfaces, we clone what's there into a new collection.
- if (TypeIsASetInterface(type))
+ // for sets and read-only set interfaces, we clone what's there into a new collection, if we can
+ if (TypeIsASetInterface(type) && !bindingPoint.IsReadOnly)
{
- if (!bindingPoint.IsReadOnly)
+ object? newValue = BindSet(type, (IEnumerable?)bindingPoint.Value, config, options);
+ if (newValue != null)
{
- object? newValue = BindSet(type, (IEnumerable?)bindingPoint.Value, config, options);
- if (newValue != null)
- {
- bindingPoint.SetValue(newValue);
- }
+ bindingPoint.SetValue(newValue);
}
+
return;
}
// For other mutable interfaces like ICollection<>, IDictionary<,> and ISet<>, we prefer copying values and setting them
// on a new instance of the interface over populating the existing instance implementing the interface.
// This has already been done, so there's not need to check again.
- if (TypeIsADictionaryInterface(type))
+ if (TypeIsADictionaryInterface(type) && !bindingPoint.IsReadOnly)
{
- if (!bindingPoint.IsReadOnly)
+ object? newValue = BindDictionaryInterface(bindingPoint.Value, type, config, options);
+ if (newValue != null)
{
- object? newValue = BindDictionaryInterface(bindingPoint.Value, type, config, options);
- if (newValue != null)
- {
- bindingPoint.SetValue(newValue);
- }
+ bindingPoint.SetValue(newValue);
}
+
return;
}
@@ -848,6 +850,16 @@ private static bool IsArrayCompatibleInterface(Type type)
|| genericTypeDefinition == typeof(IReadOnlyList<>);
}
+ private static bool IsImmutableArrayCompatibleInterface(Type type)
+ {
+ if (!type.IsInterface || !type.IsConstructedGenericType) { return false; }
+
+ Type genericTypeDefinition = type.GetGenericTypeDefinition();
+ return genericTypeDefinition == typeof(IEnumerable<>)
+ || genericTypeDefinition == typeof(IReadOnlyCollection<>)
+ || genericTypeDefinition == typeof(IReadOnlyList<>);
+ }
+
private static bool TypeIsASetInterface(Type type)
{
if (!type.IsInterface || !type.IsConstructedGenericType) { return false; }
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs
index 9eae194f02cf99..521501d5938de3 100644
--- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs
+++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs
@@ -72,6 +72,8 @@ public string ReadOnly
public ISet InstantiatedISet { get; set; } = new HashSet();
+ public ISet ISetNoSetter { get; } = new HashSet();
+
public HashSet InstantiatedHashSetWithSomeValues { get; set; } =
new HashSet(new[] {"existing1", "existing2"});
@@ -662,6 +664,27 @@ public void CanBindNonInstantiatedISet()
Assert.Equal("Yo2", options.NonInstantiatedISet.ElementAt(1));
}
+ [Fact]
+ public void CanBindISetNoSetter()
+ {
+ var dic = new Dictionary
+ {
+ {"ISetNoSetter:0", "Yo1"},
+ {"ISetNoSetter:1", "Yo2"},
+ {"ISetNoSetter:2", "Yo2"},
+ };
+ var configurationBuilder = new ConfigurationBuilder();
+ configurationBuilder.AddInMemoryCollection(dic);
+
+ var config = configurationBuilder.Build();
+
+ var options = config.Get()!;
+
+ Assert.Equal(2, options.ISetNoSetter.Count);
+ Assert.Equal("Yo1", options.ISetNoSetter.ElementAt(0));
+ Assert.Equal("Yo2", options.ISetNoSetter.ElementAt(1));
+ }
+
#if NETCOREAPP
[Fact]
public void CanBindInstantiatedIReadOnlySet()
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs
index 7367d0664cf356..4f2b5911b2b7a9 100644
--- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs
+++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs
@@ -579,7 +579,10 @@ public void AlreadyInitializedStringDictionaryBinding()
{
{"AlreadyInitializedStringDictionaryInterface:abc", "val_1"},
{"AlreadyInitializedStringDictionaryInterface:def", "val_2"},
- {"AlreadyInitializedStringDictionaryInterface:ghi", "val_3"}
+ {"AlreadyInitializedStringDictionaryInterface:ghi", "val_3"},
+
+ {"IDictionaryNoSetter:Key1", "Value1"},
+ {"IDictionaryNoSetter:Key2", "Value2"},
};
var configurationBuilder = new ConfigurationBuilder();
@@ -596,6 +599,10 @@ public void AlreadyInitializedStringDictionaryBinding()
Assert.Equal("val_1", options.AlreadyInitializedStringDictionaryInterface["abc"]);
Assert.Equal("val_2", options.AlreadyInitializedStringDictionaryInterface["def"]);
Assert.Equal("val_3", options.AlreadyInitializedStringDictionaryInterface["ghi"]);
+
+ Assert.Equal(2, options.IDictionaryNoSetter.Count);
+ Assert.Equal("Value1", options.IDictionaryNoSetter["Key1"]);
+ Assert.Equal("Value2", options.IDictionaryNoSetter["Key2"]);
}
[Fact]
@@ -1059,7 +1066,10 @@ public void CanBindInitializedIEnumerableAndTheOriginalItemsAreNotMutated()
{"AlreadyInitializedIEnumerableInterface:0", "val0"},
{"AlreadyInitializedIEnumerableInterface:1", "val1"},
{"AlreadyInitializedIEnumerableInterface:2", "val2"},
- {"AlreadyInitializedIEnumerableInterface:x", "valx"}
+ {"AlreadyInitializedIEnumerableInterface:x", "valx"},
+
+ {"ICollectionNoSetter:0", "val0"},
+ {"ICollectionNoSetter:1", "val1"},
};
var configurationBuilder = new ConfigurationBuilder();
@@ -1084,6 +1094,10 @@ public void CanBindInitializedIEnumerableAndTheOriginalItemsAreNotMutated()
Assert.Equal(2, options.ListUsedInIEnumerableFieldAndShouldNotBeTouched.Count);
Assert.Equal("This was here too", options.ListUsedInIEnumerableFieldAndShouldNotBeTouched.ElementAt(0));
Assert.Equal("Don't touch me!", options.ListUsedInIEnumerableFieldAndShouldNotBeTouched.ElementAt(1));
+
+ Assert.Equal(2, options.ICollectionNoSetter.Count);
+ Assert.Equal("val0", options.ICollectionNoSetter.ElementAt(0));
+ Assert.Equal("val1", options.ICollectionNoSetter.ElementAt(1));
}
[Fact]
@@ -1424,6 +1438,8 @@ public InitializedCollectionsOptions()
new CustomListIndirectlyDerivedFromIEnumerable();
public IReadOnlyDictionary AlreadyInitializedDictionary { get; set; }
+
+ public ICollection ICollectionNoSetter { get; } = new List();
}
private class CustomList : List
@@ -1564,6 +1580,8 @@ public OptionsWithDictionary()
public Dictionary StringDictionary { get; set; }
+ public IDictionary IDictionaryNoSetter { get; } = new Dictionary();
+
public Dictionary ObjectDictionary { get; set; }
public Dictionary> ISetDictionary { get; set; }
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs
index 54b2c5352f8c21..c910e7f8228c5d 100644
--- a/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs
+++ b/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs
@@ -201,7 +201,9 @@ public sealed class JSMarshalerType
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public struct JSMarshalerArgument
{
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public delegate void ArgumentToManagedCallback(ref JSMarshalerArgument arg, out T value);
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public delegate void ArgumentToJSCallback(ref JSMarshalerArgument arg, T value);
public void Initialize() { throw null; }
public void ToManaged(out bool value) { throw null; }
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs
index 5b932edb7965dc..2fbf3f448f5cd5 100644
--- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs
+++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs
@@ -124,7 +124,7 @@ public static void ReleaseJSOwnedObjectByGCHandle(JSMarshalerArgument* arguments
public static void CreateTaskCallback(JSMarshalerArgument* arguments_buffer)
{
ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame()
- ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return vaule
+ ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return value
try
{
JSHostImplementation.TaskCallback holder = new JSHostImplementation.TaskCallback();
@@ -195,6 +195,32 @@ public static void CompleteTask(JSMarshalerArgument* arguments_buffer)
}
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+ // the marshaled signature is:
+ // string GetManagedStackTrace(GCHandle exception)
+ public static void GetManagedStackTrace(JSMarshalerArgument* arguments_buffer)
+ {
+ ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame()
+ ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return value
+ ref JSMarshalerArgument arg_1 = ref arguments_buffer[2];// initialized and set by caller
+ try
+ {
+ GCHandle exception_gc_handle = (GCHandle)arg_1.slot.GCHandle;
+ if (exception_gc_handle.Target is Exception exception)
+ {
+ arg_return.ToJS(exception.StackTrace);
+ }
+ else
+ {
+ throw new InvalidOperationException("Exception is null");
+ }
+ }
+ catch (Exception ex)
+ {
+ arg_exc.ToJS(ex);
+ }
+ }
+
#if FEATURE_WASM_THREADS
[MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs
index f3101e881fe9ac..13876867c8a544 100644
--- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs
+++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs
@@ -13,12 +13,14 @@ public partial struct JSMarshalerArgument
/// Helps with marshaling of the Task result or Function arguments.
/// It's used by JSImport code generator and should not be used by developers in source code.
///
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public delegate void ArgumentToManagedCallback(ref JSMarshalerArgument arg, out T value);
///
/// Helps with marshaling of the Task result or Function arguments.
/// It's used by JSImport code generator and should not be used by developers in source code.
///
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public delegate void ArgumentToJSCallback(ref JSMarshalerArgument arg, T value);
///
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs
index a8966dcaf521d0..79e9e3e0cecf50 100644
--- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs
+++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs
@@ -1358,11 +1358,28 @@ public void JsExportException(Exception value, string clazz)
[Fact]
public void JsExportThrows()
{
- var ex = Assert.Throws(() => JavaScriptTestHelper.invoke1_String("-t-e-s-t-", nameof(JavaScriptTestHelper.Throw)));
+ var ex = Assert.Throws(() => JavaScriptTestHelper.invoke1_String("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport)));
Assert.DoesNotContain("Unexpected error", ex.Message);
Assert.Contains("-t-e-s-t-", ex.Message);
}
+ [Fact]
+ public void JsExportCatchToString()
+ {
+ var toString = JavaScriptTestHelper.catch1toString("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport));
+ Assert.DoesNotContain("Unexpected error", toString);
+ Assert.Contains("-t-e-s-t-", toString);
+ Assert.DoesNotContain(nameof(JavaScriptTestHelper.ThrowFromJSExport), toString);
+ }
+
+ [Fact]
+ public void JsExportCatchStack()
+ {
+ var stack = JavaScriptTestHelper.catch1stack("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport));
+ Assert.Contains(nameof(JavaScriptTestHelper.ThrowFromJSExport), stack);
+ Assert.Contains("catch1stack", stack);
+ }
+
#endregion Exception
#region JSObject
@@ -1906,12 +1923,12 @@ private void JsImportTest(T value
var exThrow0 = Assert.Throws(() => JavaScriptTestHelper.throw0());
Assert.Contains("throw-0-msg", exThrow0.Message);
Assert.DoesNotContain(" at ", exThrow0.Message);
- Assert.Contains(" at Module.throw0", exThrow0.StackTrace);
+ Assert.Contains("throw0fn", exThrow0.StackTrace);
var exThrow1 = Assert.Throws(() => throw1(value));
Assert.Contains("throw1-msg", exThrow1.Message);
Assert.DoesNotContain(" at ", exThrow1.Message);
- Assert.Contains(" at Module.throw1", exThrow1.StackTrace);
+ Assert.Contains("throw1fn", exThrow1.StackTrace);
// anything is a system.object, sometimes it would be JSObject wrapper
if (typeof(T).IsPrimitive)
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs
index b5a89b7f48fe98..67fe77cfe5fe80 100644
--- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs
+++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs
@@ -32,8 +32,14 @@ public static void ConsoleWriteLine([JSMarshalAs] string message)
Console.WriteLine(message);
}
+ [JSImport("catch1toString", "JavaScriptTestHelper")]
+ public static partial string catch1toString(string message, string functionName);
+
+ [JSImport("catch1stack", "JavaScriptTestHelper")]
+ public static partial string catch1stack(string message, string functionName);
+
[JSExport]
- public static void Throw(string message)
+ public static void ThrowFromJSExport(string message)
{
throw new ArgumentException(message);
}
@@ -57,7 +63,7 @@ public static DateTime Now()
[return: JSMarshalAs]
internal static partial string getClass1();
- [JSImport("throw0", "JavaScriptTestHelper")]
+ [JSImport("throw0fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial void throw0();
@@ -215,7 +221,7 @@ internal static partial void Relaxed(string a1, Exception ex,
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Int32([JSMarshalAs] int value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial int throw1_Int32([JSMarshalAs] int value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -241,7 +247,7 @@ public static int EchoInt32([JSMarshalAs] int arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_String([JSMarshalAs] string value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial string throw1_String([JSMarshalAs] string value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -273,7 +279,7 @@ public static string EchoString([JSMarshalAs] string arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Object([JSMarshalAs] object value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial object throw1_Object([JSMarshalAs] object value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -299,7 +305,7 @@ public static object EchoObject([JSMarshalAs] object arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Exception([JSMarshalAs] Exception value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial Exception throw1_Exception([JSMarshalAs] Exception value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -431,7 +437,7 @@ public static Func BackFuncOfIntInt([JSMarshalAs]
internal static partial bool identity1_Boolean([JSMarshalAs] bool value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool throw1_Boolean([JSMarshalAs] bool value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -458,7 +464,7 @@ public static bool EchoBoolean([JSMarshalAs] bool arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Char([JSMarshalAs] char value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial char throw1_Char([JSMarshalAs] char value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -484,7 +490,7 @@ public static char EchoChar([JSMarshalAs] char arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Byte([JSMarshalAs] byte value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial byte throw1_Byte([JSMarshalAs] byte value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -510,7 +516,7 @@ public static byte EchoByte([JSMarshalAs] byte arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Int16([JSMarshalAs] short value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial short throw1_Int16([JSMarshalAs] short value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -536,7 +542,7 @@ public static short EchoInt16([JSMarshalAs] short arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Int52([JSMarshalAs] long value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial long throw1_Int52([JSMarshalAs] long value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -562,7 +568,7 @@ public static long EchoInt52([JSMarshalAs] long arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_BigInt64([JSMarshalAs] long value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial long throw1_BigInt64([JSMarshalAs] long value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -588,7 +594,7 @@ public static long EchoBigInt64([JSMarshalAs] long arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Double([JSMarshalAs] double value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial double throw1_Double([JSMarshalAs] double value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -614,7 +620,7 @@ public static double EchoDouble([JSMarshalAs] double arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_Single([JSMarshalAs] float value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial float throw1_Single([JSMarshalAs] float value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -640,7 +646,7 @@ public static float EchoSingle([JSMarshalAs] float arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_IntPtr([JSMarshalAs] IntPtr value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial IntPtr throw1_IntPtr([JSMarshalAs] IntPtr value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -667,7 +673,7 @@ public static IntPtr EchoIntPtr([JSMarshalAs] IntPtr arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal unsafe static partial bool identity1_VoidPtr([JSMarshalAs] void* value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal unsafe static partial void* throw1_VoidPtr([JSMarshalAs] void* value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -693,7 +699,7 @@ public static IntPtr EchoIntPtr([JSMarshalAs] IntPtr arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_DateTime([JSMarshalAs] DateTime value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial DateTime throw1_DateTime([JSMarshalAs] DateTime value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -719,7 +725,7 @@ public static DateTime EchoDateTime([JSMarshalAs] DateTime arg1)
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_DateTimeOffset([JSMarshalAs] DateTimeOffset value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial DateTimeOffset throw1_DateTimeOffset([JSMarshalAs] DateTimeOffset value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -746,7 +752,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_NullableBoolean([JSMarshalAs] bool? value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool? throw1_NullableBoolean([JSMarshalAs] bool? value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -773,7 +779,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_NullableInt32([JSMarshalAs] int? value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial int? throw1_NullableInt32([JSMarshalAs] int? value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -800,7 +806,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_NullableBigInt64([JSMarshalAs] long? value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial long? throw1_NullableBigInt64([JSMarshalAs] long? value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -827,7 +833,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_NullableIntPtr([JSMarshalAs] IntPtr? value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial IntPtr? throw1_NullableIntPtr([JSMarshalAs] IntPtr? value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -854,7 +860,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_NullableDouble([JSMarshalAs] double? value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial double? throw1_NullableDouble([JSMarshalAs] double? value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -881,7 +887,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_NullableDateTime([JSMarshalAs] DateTime? value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial DateTime? throw1_NullableDateTime([JSMarshalAs] DateTime? value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -907,7 +913,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT
[JSImport("identity1", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial bool identity1_JSObject([JSMarshalAs] JSObject value);
- [JSImport("throw1", "JavaScriptTestHelper")]
+ [JSImport("throw1fn", "JavaScriptTestHelper")]
[return: JSMarshalAs]
internal static partial JSObject throw1_JSObject([JSMarshalAs] JSObject value);
[JSImport("invoke1", "JavaScriptTestHelper")]
@@ -1236,4 +1242,4 @@ public partial record struct NestedRecordStruct
[System.Runtime.InteropServices.JavaScript.JSExport]
public static string EchoString(string message) => message + "85";
}
-}
\ No newline at end of file
+}
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs
index 314e715e16b815..0811be477c64f6 100644
--- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs
+++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs
@@ -105,12 +105,34 @@ export function retrieve1() {
return val;
}
-export function throw0() {
+export function throw0fn() {
//console.log(`throw0()`)
throw new Error('throw-0-msg');
}
-export function throw1(arg1) {
+export function catch1toString(message, functionName) {
+ const JavaScriptTestHelper = dllExports.System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper;
+ const fn = JavaScriptTestHelper[functionName];
+ try {
+ fn(message);
+ return "bad";
+ } catch (err) {
+ return err.toString();
+ }
+}
+
+export function catch1stack(message, functionName) {
+ const JavaScriptTestHelper = dllExports.System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper;
+ const fn = JavaScriptTestHelper[functionName];
+ try {
+ fn(message);
+ return "bad";
+ } catch (err) {
+ return err.stack;
+ }
+}
+
+export function throw1fn(arg1) {
//console.log(`throw1(arg1:${arg1 !== null ? arg1 : ''})`)
throw new Error('throw1-msg ' + arg1);
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxExtensions.cs
index 20400c4721369e..3fea4b0fae2e21 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxExtensions.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/SyntaxExtensions.cs
@@ -33,7 +33,17 @@ public static Location FindTypeExpressionOrNullLocation(this AttributeArgumentSy
switch (attributeTarget.Identifier.Kind())
{
case SyntaxKind.ReturnKeyword:
- return ((IMethodSymbol)targetSymbol).GetReturnTypeAttributes().First(attributeSyntaxLocationMatches);
+ if (targetSymbol is IMethodSymbol method)
+ {
+ // Sometimes an attribute is put on a symbol that is nested within the containing symbol.
+ // For example, the ContainingSymbol for an AttributeSyntax on a local function have a ContainingSymbol of the method.
+ // Since this method is internal and the callers don't care about attributes on local functions,
+ // we just allow this method to return null in those cases.
+ return method.GetReturnTypeAttributes().FirstOrDefault(attributeSyntaxLocationMatches);
+ }
+ // An attribute on the return value of a delegate type's Invoke method has a ContainingSymbol of the delegate type.
+ // We don't care about the attributes in this case for the callers, so we'll just return null.
+ return null;
case SyntaxKind.AssemblyKeyword:
return targetSymbol.ContainingAssembly.GetAttributes().First(attributeSyntaxLocationMatches);
case SyntaxKind.ModuleKeyword:
@@ -43,7 +53,8 @@ public static Location FindTypeExpressionOrNullLocation(this AttributeArgumentSy
}
}
// Sometimes an attribute is put on a symbol that is nested within the containing symbol.
- // For example, the ContainingSymbol for an AttributeSyntax on a parameter have a ContainingSymbol of the method.
+ // For example, the ContainingSymbol for an AttributeSyntax on a parameter have a ContainingSymbol of the method
+ // and an AttributeSyntax on a local function have a ContainingSymbol of the containing method.
// Since this method is internal and the callers don't care about attributes on parameters, we just allow
// this method to return null in those cases.
return targetSymbol.GetAttributes().FirstOrDefault(attributeSyntaxLocationMatches);
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs
index 582568718722b5..5b8769e19c9ee2 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs
@@ -272,8 +272,18 @@ public class X
{
void Foo([MarshalAs(UnmanagedType.I4)] int i)
{
+ [return:MarshalAs(UnmanagedType.I4)]
+ [SkipLocalsInit]
+ static int Local()
+ {
+ return 0;
+ }
}
}
+
+ [return:MarshalAs(UnmanagedType.I4)]
+ delegate int Y();
+
""";
await VerifyCS.VerifyAnalyzerAsync(source);
diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs
index 015f36c8a979f7..acd7df3a9f8077 100644
--- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTest.cs
@@ -62,19 +62,27 @@ public async Task VerifyComputeHashAsync(int size)
[ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)]
public async Task ComputeHashAsync_SupportsCancellation()
{
- using (CancellationTokenSource cancellationSource = new CancellationTokenSource(100))
- using (PositionValueStream stream = new SlowPositionValueStream(10000))
+ using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
+ using (PositionValueStream stream = new SelfCancelingStream(10000, cancellationSource))
using (HashAlgorithm hash = new SummingTestHashAlgorithm())
{
+ // The stream has a length longer than ComputeHashAsync's read buffer,
+ // so ReadAsync will get called multiple times.
+ // The first call succeeds, but moves the cancellation source to canceled,
+ // and the second call then fails with an OperationCanceledException, canceling the
+ // whole operation.
await Assert.ThrowsAnyAsync(
() => hash.ComputeHashAsync(stream, cancellationSource.Token));
+
+ Assert.True(cancellationSource.IsCancellationRequested);
}
}
[Fact]
public void ComputeHashAsync_Disposed()
{
- using (PositionValueStream stream = new SlowPositionValueStream(10000))
+ using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
+ using (PositionValueStream stream = new SelfCancelingStream(10000, cancellationSource))
using (HashAlgorithm hash = new SummingTestHashAlgorithm())
{
hash.Dispose();
@@ -85,6 +93,10 @@ public void ComputeHashAsync_Disposed()
// Not returning or awaiting the Task, it never got created.
hash.ComputeHashAsync(stream);
});
+
+ // If SelfCancelingStream.Read (or ReadAsync) was called it will trip cancellation,
+ // so use that as a signal for whether or not the stream was ever read from.
+ Assert.False(cancellationSource.IsCancellationRequested, "Stream.Read was invoked");
}
}
@@ -123,15 +135,19 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize)
// implementations by verifying the right value is produced.
}
- private class SlowPositionValueStream : PositionValueStream
+ private class SelfCancelingStream : PositionValueStream
{
- public SlowPositionValueStream(int totalCount) : base(totalCount)
+ private readonly CancellationTokenSource _cancellationSource;
+
+ public SelfCancelingStream(int totalCount, CancellationTokenSource cancellationSource)
+ : base(totalCount)
{
+ _cancellationSource = cancellationSource;
}
public override int Read(byte[] buffer, int offset, int count)
{
- System.Threading.Thread.Sleep(1000);
+ _cancellationSource.Cancel(throwOnFirstException: true);
return base.Read(buffer, offset, count);
}
}
diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj
index e17ce01c770357..8cd779f5a02188 100644
--- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj
+++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj
@@ -36,6 +36,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET
+
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/AppContextSwitchHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/AppContextSwitchHelper.cs
new file mode 100644
index 00000000000000..9c028f02165171
--- /dev/null
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/AppContextSwitchHelper.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json
+{
+ internal static class AppContextSwitchHelper
+ {
+ public static bool IsSourceGenReflectionFallbackEnabled => s_isSourceGenReflectionFallbackEnabled;
+
+ private static readonly bool s_isSourceGenReflectionFallbackEnabled =
+ AppContext.TryGetSwitch(
+ switchName: "System.Text.Json.Serialization.EnableSourceGenReflectionFallback",
+ isEnabled: out bool value)
+ ? value : false;
+ }
+}
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs
index 596a9c37bae488..fa543671792fb0 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs
@@ -628,7 +628,20 @@ internal void InitializeForReflectionSerializer()
// Even if a resolver has already been specified, we need to root
// the default resolver to gain access to the default converters.
DefaultJsonTypeInfoResolver defaultResolver = DefaultJsonTypeInfoResolver.RootDefaultInstance();
- _typeInfoResolver ??= defaultResolver;
+
+ switch (_typeInfoResolver)
+ {
+ case null:
+ // Use the default reflection-based resolver if no resolver has been specified.
+ _typeInfoResolver = defaultResolver;
+ break;
+
+ case JsonSerializerContext ctx when AppContextSwitchHelper.IsSourceGenReflectionFallbackEnabled:
+ // .NET 6 compatibility mode: enable fallback to reflection metadata for JsonSerializerContext
+ _effectiveJsonTypeInfoResolver = JsonTypeInfoResolver.Combine(ctx, defaultResolver);
+ break;
+ }
+
IsImmutable = true;
_isInitializedForReflectionSerializer = true;
}
@@ -636,6 +649,9 @@ internal void InitializeForReflectionSerializer()
internal bool IsInitializedForReflectionSerializer => _isInitializedForReflectionSerializer;
private volatile bool _isInitializedForReflectionSerializer;
+ // Only populated in .NET 6 compatibility mode encoding reflection fallback in source gen
+ private IJsonTypeInfoResolver? _effectiveJsonTypeInfoResolver;
+
internal void InitializeForMetadataGeneration()
{
if (_typeInfoResolver is null)
@@ -648,7 +664,7 @@ internal void InitializeForMetadataGeneration()
private JsonTypeInfo? GetTypeInfoNoCaching(Type type)
{
- JsonTypeInfo? info = _typeInfoResolver?.GetTypeInfo(type, this);
+ JsonTypeInfo? info = (_effectiveJsonTypeInfoResolver ?? _typeInfoResolver)?.GetTypeInfo(type, this);
if (info != null)
{
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs
index a91467a9943a3e..05cd443bccf5ac 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs
@@ -437,9 +437,18 @@ public static void Options_JsonSerializerContext_DoesNotFallbackToReflection()
}
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
- [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
- public static void Options_JsonSerializerContext_GetConverter_DoesNotFallBackToReflectionConverter()
+ [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ [InlineData(false)]
+ [InlineData(true)]
+ public static void Options_JsonSerializerContext_GetConverter_DoesNotFallBackToReflectionConverter(bool isCompatibilitySwitchExplicitlyDisabled)
{
+ var options = new RemoteInvokeOptions();
+
+ if (isCompatibilitySwitchExplicitlyDisabled)
+ {
+ options.RuntimeConfigurationOptions.Add("System.Text.Json.Serialization.EnableSourceGenReflectionFallback", false);
+ }
+
RemoteExecutor.Invoke(static () =>
{
JsonContext context = JsonContext.Default;
@@ -460,7 +469,40 @@ public static void Options_JsonSerializerContext_GetConverter_DoesNotFallBackToR
Assert.Throws(() => context.Options.GetConverter(typeof(MyClass)));
Assert.Throws(() => JsonSerializer.Serialize(unsupportedValue, context.Options));
- }).Dispose();
+ }, options).Dispose();
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public static void Options_JsonSerializerContext_Net6CompatibilitySwitch_FallsBackToReflectionResolver()
+ {
+ var options = new RemoteInvokeOptions
+ {
+ RuntimeConfigurationOptions =
+ {
+ ["System.Text.Json.Serialization.EnableSourceGenReflectionFallback"] = true
+ }
+ };
+
+ RemoteExecutor.Invoke(static () =>
+ {
+ var unsupportedValue = new MyClass { Value = "value" };
+
+ // JsonSerializerContext does not return metadata for the type
+ Assert.Null(JsonContext.Default.GetTypeInfo(typeof(MyClass)));
+
+ // Serialization fails using the JsonSerializerContext overload
+ Assert.Throws(() => JsonSerializer.Serialize(unsupportedValue, unsupportedValue.GetType(), JsonContext.Default));
+
+ // Serialization uses reflection fallback using the JsonSerializerOptions overload
+ string json = JsonSerializer.Serialize(unsupportedValue, JsonContext.Default.Options);
+ JsonTestHelper.AssertJsonEqual("""{"Value":"value", "Thing":null}""", json);
+
+ // A converter can be resolved when looking up JsonSerializerOptions
+ JsonConverter converter = JsonContext.Default.Options.GetConverter(typeof(MyClass));
+ Assert.IsAssignableFrom>(converter);
+
+ }, options).Dispose();
}
[Fact]
diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberObjectsExplorer.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberObjectsExplorer.cs
index 24f4d8522cb845..38c6540b812d6c 100644
--- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberObjectsExplorer.cs
+++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberObjectsExplorer.cs
@@ -238,6 +238,9 @@ public static async Task ExpandFieldValues(
JObject fieldValue = await ReadFieldValue(sdbHelper, retDebuggerCmdReader, field, id.Value, typeInfo, valtype, isOwn, parentTypeId, getCommandOptions, token);
numFieldsRead++;
+ if (typeInfo.Info.IsNonUserCode && getCommandOptions.HasFlag(GetObjectCommandOptions.JustMyCode) && field.Attributes.HasFlag(FieldAttributes.Private))
+ continue;
+
if (!Enum.TryParse(fieldValue["__state"].Value(), out DebuggerBrowsableState fieldState)
|| fieldState == DebuggerBrowsableState.Collapsed)
{
@@ -311,7 +314,7 @@ public static async Task> ExpandPropertyValues(
int typeId,
string typeName,
ArraySegment getterParamsBuffer,
- bool isAutoExpandable,
+ GetObjectCommandOptions getCommandOptions,
DotnetObjectId objectId,
bool isValueType,
bool isOwn,
@@ -347,6 +350,10 @@ public static async Task> ExpandPropertyValues(
MethodAttributes getterAttrs = getterInfo.Info.Attributes;
MethodAttributes getterMemberAccessAttrs = getterAttrs & MethodAttributes.MemberAccessMask;
MethodAttributes vtableLayout = getterAttrs & MethodAttributes.VtableLayoutMask;
+
+ if (typeInfo.Info.IsNonUserCode && getCommandOptions.HasFlag(GetObjectCommandOptions.JustMyCode) && getterMemberAccessAttrs == MethodAttributes.Private)
+ continue;
+
bool isNewSlot = (vtableLayout & MethodAttributes.NewSlot) == MethodAttributes.NewSlot;
typePropertiesBrowsableInfo.TryGetValue(propName, out DebuggerBrowsableState? state);
@@ -454,7 +461,7 @@ async Task AddProperty(
{
string returnTypeName = await sdbHelper.GetReturnType(getMethodId, token);
JObject propRet = null;
- if (isAutoExpandable || (state is DebuggerBrowsableState.RootHidden && IsACollectionType(returnTypeName)))
+ if (getCommandOptions.HasFlag(GetObjectCommandOptions.AutoExpandable) || getCommandOptions.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute) || (state is DebuggerBrowsableState.RootHidden && IsACollectionType(returnTypeName)))
{
try
{
@@ -568,10 +575,6 @@ public static async Task GetObjectMemberValues(
for (int i = 0; i < typeIdsCnt; i++)
{
int typeId = typeIdsIncludingParents[i];
- var typeInfo = await sdbHelper.GetTypeInfo(typeId, token);
-
- if (typeInfo.Info.IsNonUserCode && getCommandType.HasFlag(GetObjectCommandOptions.JustMyCode))
- continue;
int parentTypeId = i + 1 < typeIdsCnt ? typeIdsIncludingParents[i + 1] : -1;
string typeName = await sdbHelper.GetTypeName(typeId, token);
@@ -604,7 +607,7 @@ public static async Task GetObjectMemberValues(
typeId,
typeName,
getPropertiesParamBuffer,
- getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute),
+ getCommandType,
id,
isValueType: false,
isOwn,
diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
index 8ff9f8ae9af99e..fb17d2e72453b3 100644
--- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
+++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
@@ -60,7 +60,8 @@ internal enum GetObjectCommandOptions
ForDebuggerProxyAttribute = 8,
ForDebuggerDisplayAttribute = 16,
WithProperties = 32,
- JustMyCode = 64
+ JustMyCode = 64,
+ AutoExpandable = 128
}
internal enum CommandSet {
diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs
index c2a2513f00ba19..07b2036caacb3b 100644
--- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs
+++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs
@@ -293,7 +293,7 @@ public async Task ExpandPropertyValues(MonoSDBHelper sdbHelper, bool splitMember
typeId,
className,
Buffer,
- autoExpand,
+ autoExpand ? GetObjectCommandOptions.AutoExpandable : GetObjectCommandOptions.None,
Id,
isValueType: true,
isOwn: i == 0,
diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs
index 9973811a56e499..e05f4d682db641 100644
--- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs
+++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs
@@ -1067,7 +1067,11 @@ await EvaluateAndCheck(
{
myField = TNumber(0),
myField2 = TNumber(0),
- }, "this_props", num_fields: 2);
+ propB = TGetter("propB"),
+ propC = TGetter("propC"),
+ e = TNumber(50),
+ f = TNumber(60),
+ }, "this_props", num_fields: 6);
}
else
{
diff --git a/src/mono/wasm/debugger/tests/debugger-test-with-non-user-code-class/test.cs b/src/mono/wasm/debugger/tests/debugger-test-with-non-user-code-class/test.cs
index af11a6329d0d26..1626d47d5d4e1f 100644
--- a/src/mono/wasm/debugger/tests/debugger-test-with-non-user-code-class/test.cs
+++ b/src/mono/wasm/debugger/tests/debugger-test-with-non-user-code-class/test.cs
@@ -16,11 +16,11 @@ public class ClassNonUserCodeToInheritThatInheritsFromNormalClass : NormalClass
private int d;
public int e;
protected int f;
- public int G
+ private int G
{
get {return f + 1;}
}
- public int H => f;
+ private int H => f;
public ClassNonUserCodeToInheritThatInheritsFromNormalClass()
{
diff --git a/src/mono/wasm/debugger/tests/debugger-test-without-debug-symbols-to-load/test.cs b/src/mono/wasm/debugger/tests/debugger-test-without-debug-symbols-to-load/test.cs
index 5dcdc29f93f2d0..4899b8869ef402 100644
--- a/src/mono/wasm/debugger/tests/debugger-test-without-debug-symbols-to-load/test.cs
+++ b/src/mono/wasm/debugger/tests/debugger-test-without-debug-symbols-to-load/test.cs
@@ -10,11 +10,11 @@ public class ClassWithoutDebugSymbolsToInherit
private int d;
public int e;
protected int f;
- public int G
+ private int G
{
get {return f + 1;}
}
- public int H => f;
+ private int H => f;
public ClassWithoutDebugSymbolsToInherit()
{
diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
index b8f52c788f0d2b..73a225cf5e16c4 100644
--- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
+++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
@@ -1300,11 +1300,11 @@ public class ClassNonUserCodeToInherit
private int d;
public int e;
protected int f;
- public int G
+ private int G
{
get {return f + 1;}
}
- public int H => f;
+ private int H => f;
public ClassNonUserCodeToInherit()
{
diff --git a/src/mono/wasm/runtime/logging.ts b/src/mono/wasm/runtime/logging.ts
index 2d40d7c4d20e29..cdb2d00dba723d 100644
--- a/src/mono/wasm/runtime/logging.ts
+++ b/src/mono/wasm/runtime/logging.ts
@@ -62,8 +62,9 @@ export function mono_wasm_symbolicate_string(message: string): string {
export function mono_wasm_stringify_as_error_with_stack(err: Error | string): string {
let errObj: any = err;
- if (!(err instanceof Error))
- errObj = new Error(err);
+ if (!(errObj instanceof Error)) {
+ errObj = new Error(errObj);
+ }
// Error
return mono_wasm_symbolicate_string(errObj.stack);
diff --git a/src/mono/wasm/runtime/managed-exports.ts b/src/mono/wasm/runtime/managed-exports.ts
index 09f6d9a33d0241..65186e4c0b270f 100644
--- a/src/mono/wasm/runtime/managed-exports.ts
+++ b/src/mono/wasm/runtime/managed-exports.ts
@@ -7,7 +7,7 @@ import { Module, runtimeHelpers, ENVIRONMENT_IS_PTHREAD } from "./imports";
import { alloc_stack_frame, get_arg, get_arg_gc_handle, MarshalerType, set_arg_type, set_gc_handle } from "./marshal";
import { invoke_method_and_handle_exception } from "./invoke-cs";
import { marshal_array_to_cs_impl, marshal_exception_to_cs, marshal_intptr_to_cs } from "./marshal-to-cs";
-import { marshal_int32_to_js, marshal_task_to_js } from "./marshal-to-js";
+import { marshal_int32_to_js, marshal_string_to_js, marshal_task_to_js } from "./marshal-to-js";
export function init_managed_exports(): void {
const anyModule = Module as any;
@@ -34,6 +34,9 @@ export function init_managed_exports(): void {
mono_assert(complete_task_method, "Can't find CompleteTask method");
const call_delegate_method = get_method("CallDelegate");
mono_assert(call_delegate_method, "Can't find CallDelegate method");
+ const get_managed_stack_trace_method = get_method("GetManagedStackTrace");
+ mono_assert(get_managed_stack_trace_method, "Can't find GetManagedStackTrace method");
+
runtimeHelpers.javaScriptExports.call_entry_point = (entry_point: MonoMethod, program_args?: string[]) => {
const sp = anyModule.stackSave();
try {
@@ -134,6 +137,22 @@ export function init_managed_exports(): void {
anyModule.stackRestore(sp);
}
};
+ runtimeHelpers.javaScriptExports.get_managed_stack_trace = (exception_gc_handle: GCHandle) => {
+ const sp = anyModule.stackSave();
+ try {
+ const args = alloc_stack_frame(3);
+
+ const arg1 = get_arg(args, 2);
+ set_arg_type(arg1, MarshalerType.Exception);
+ set_gc_handle(arg1, exception_gc_handle);
+
+ invoke_method_and_handle_exception(get_managed_stack_trace_method, args);
+ const res = get_arg(args, 1);
+ return marshal_string_to_js(res);
+ } finally {
+ anyModule.stackRestore(sp);
+ }
+ };
if (install_sync_context) {
runtimeHelpers.javaScriptExports.install_synchronization_context = () => {
diff --git a/src/mono/wasm/runtime/marshal-to-js.ts b/src/mono/wasm/runtime/marshal-to-js.ts
index 318d10580ffec0..aac0155406c4ec 100644
--- a/src/mono/wasm/runtime/marshal-to-js.ts
+++ b/src/mono/wasm/runtime/marshal-to-js.ts
@@ -32,7 +32,7 @@ export function initialize_marshalers_to_js(): void {
cs_to_js_marshalers.set(MarshalerType.Single, _marshal_float_to_js);
cs_to_js_marshalers.set(MarshalerType.IntPtr, _marshal_intptr_to_js);
cs_to_js_marshalers.set(MarshalerType.Double, _marshal_double_to_js);
- cs_to_js_marshalers.set(MarshalerType.String, _marshal_string_to_js);
+ cs_to_js_marshalers.set(MarshalerType.String, marshal_string_to_js);
cs_to_js_marshalers.set(MarshalerType.Exception, marshal_exception_to_js);
cs_to_js_marshalers.set(MarshalerType.JSException, marshal_exception_to_js);
cs_to_js_marshalers.set(MarshalerType.JSObject, _marshal_js_object_to_js);
@@ -353,7 +353,7 @@ export function mono_wasm_marshal_promise(args: JSMarshalerArguments): void {
set_arg_type(exc, MarshalerType.None);
}
-function _marshal_string_to_js(arg: JSMarshalerArgument): string | null {
+export function marshal_string_to_js(arg: JSMarshalerArgument): string | null {
const type = get_arg_type(arg);
if (type == MarshalerType.None) {
return null;
@@ -383,7 +383,7 @@ export function marshal_exception_to_js(arg: JSMarshalerArgument): Error | null
let result = _lookup_js_owned_object(gc_handle);
if (result === null || result === undefined) {
// this will create new ManagedError
- const message = _marshal_string_to_js(arg);
+ const message = marshal_string_to_js(arg);
result = new ManagedError(message!);
setup_managed_proxy(result, gc_handle);
@@ -462,7 +462,7 @@ function _marshal_array_to_js_impl(arg: JSMarshalerArgument, element_type: Marsh
result = new Array(length);
for (let index = 0; index < length; index++) {
const element_arg = get_arg(buffer_ptr, index);
- result[index] = _marshal_string_to_js(element_arg);
+ result[index] = marshal_string_to_js(element_arg);
}
cwraps.mono_wasm_deregister_root(buffer_ptr);
}
diff --git a/src/mono/wasm/runtime/marshal.ts b/src/mono/wasm/runtime/marshal.ts
index 77bec6b6aa762f..f20a620c5fb76b 100644
--- a/src/mono/wasm/runtime/marshal.ts
+++ b/src/mono/wasm/runtime/marshal.ts
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles";
-import { Module } from "./imports";
+import { Module, runtimeHelpers } from "./imports";
import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8 } from "./memory";
import { mono_wasm_new_external_root } from "./roots";
import { mono_assert, GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot } from "./types";
@@ -316,13 +316,31 @@ export class ManagedObject implements IDisposable {
}
export class ManagedError extends Error implements IDisposable {
+ private superStack: any;
constructor(message: string) {
super(message);
+ this.superStack = Object.getOwnPropertyDescriptor(this, "stack"); // this works on Chrome
+ Object.defineProperty(this, "stack", {
+ get: this.getManageStack,
+ });
}
- get stack(): string | undefined {
- //todo implement lazy managed stack strace from this[js_owned_gc_handle_symbol]!
- return super.stack;
+ getSuperStack() {
+ if (this.superStack) {
+ return this.superStack.value;
+ }
+ return super.stack; // this works on FF
+ }
+
+ getManageStack() {
+ const gc_handle = (this)[js_owned_gc_handle_symbol];
+ if (gc_handle) {
+ const managed_stack = runtimeHelpers.javaScriptExports.get_managed_stack_trace(gc_handle);
+ if (managed_stack) {
+ return managed_stack + "\n" + this.getSuperStack();
+ }
+ }
+ return this.getSuperStack();
}
dispose(): void {
@@ -332,10 +350,6 @@ export class ManagedError extends Error implements IDisposable {
get isDisposed(): boolean {
return (this)[js_owned_gc_handle_symbol] === GCHandleNull;
}
-
- toString(): string {
- return `ManagedError(gc_handle: ${(this)[js_owned_gc_handle_symbol]})`;
- }
}
export function get_signature_marshaler(signature: JSFunctionSignature, index: number): JSHandle {
diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts
index ea01f16a9e5c85..3664532e54c5e9 100644
--- a/src/mono/wasm/runtime/types.ts
+++ b/src/mono/wasm/runtime/types.ts
@@ -411,6 +411,9 @@ export interface JavaScriptExports {
// the marshaled signature is: void InstallSynchronizationContext()
install_synchronization_context(): void;
+
+ // the marshaled signature is: string GetManagedStackTrace(GCHandle exception)
+ get_managed_stack_trace(exception_gc_handle: GCHandle): string | null
}
export type MarshalerToJs = (arg: JSMarshalerArgument, sig?: JSMarshalerType, res_converter?: MarshalerToJs, arg1_converter?: MarshalerToCs, arg2_converter?: MarshalerToCs) => any;
diff --git a/src/mono/wasm/templates/templates/browser/README.md b/src/mono/wasm/templates/templates/browser/README.md
index f3c4ddce82ffc9..8e1339897bef46 100644
--- a/src/mono/wasm/templates/templates/browser/README.md
+++ b/src/mono/wasm/templates/templates/browser/README.md
@@ -2,20 +2,20 @@
## Build
-You can build the applcation from Visual Studio or by dotnet cli
+You can build the application from Visual Studio or by dotnet cli
```
-dotnet build -c Debug/Release -r browser-wasm
+dotnet build -c Debug/Release
```
After building the application, the result is in the `bin/$(Configuration)/net7.0/browser-wasm/AppBundle` directory.
## Run
-You can build the applcation from Visual Studio or by dotnet cli
+You can build the application from Visual Studio or by dotnet cli
```
-dotnet run -c Debug/Release -r browser-wasm
+dotnet run -c Debug/Release
```
Or you can start any static file server from the AppBundle directory
diff --git a/src/mono/wasm/templates/templates/console/README.md b/src/mono/wasm/templates/templates/console/README.md
index a3b8dbc660e5d0..84fd14b27897e2 100644
--- a/src/mono/wasm/templates/templates/console/README.md
+++ b/src/mono/wasm/templates/templates/console/README.md
@@ -2,20 +2,20 @@
## Build
-You can build the applcation from Visual Studio or by dotnet cli
+You can build the application from Visual Studio or by dotnet cli
```
-dotnet build -c Debug/Release -r browser-wasm
+dotnet build -c Debug/Release
```
After building the application, the result is in the `bin/$(Configuration)/net7.0/browser-wasm/AppBundle` directory.
## Run
-You can build the applcation from Visual Studio or by dotnet cli
+You can build the application from Visual Studio or by dotnet cli
```
-dotnet run -c Debug/Release -r browser-wasm -h=nodejs
+dotnet run -c Debug/Release
```
Or you can start any static file server from the AppBundle directory
diff --git a/src/tests/JIT/Regression/JitBlue/ImageSharp_2117/ImageSharp_2117.cs b/src/tests/JIT/Regression/JitBlue/ImageSharp_2117/ImageSharp_2117.cs
new file mode 100644
index 00000000000000..415d9b00f5c8a6
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/ImageSharp_2117/ImageSharp_2117.cs
@@ -0,0 +1,37 @@
+// 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.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+public unsafe class ImageSharp_2117
+{
+ public static int Main(string[] args)
+ {
+ if (Sse.IsSupported)
+ {
+ Vector128 fnan = Vector128.Create(float.NaN);
+ Vector128 res1 = Sse.Max(Sse.LoadVector128((float*)(&fnan)), Vector128.Zero);
+ Vector128 res2 = Sse.Min(Sse.LoadVector128((float*)(&fnan)), Vector128.Zero);
+
+ if (float.IsNaN(res1[0]) || float.IsNaN(res2[0]))
+ {
+ return 0;
+ }
+ }
+
+ if (Sse2.IsSupported)
+ {
+ Vector128 dnan = Vector128.Create(double.NaN);
+ Vector128 res3 = Sse2.Max(Sse2.LoadVector128((double*)(&dnan)), Vector128.Zero);
+ Vector128 res4 = Sse2.Min(Sse2.LoadVector128((double*)(&dnan)), Vector128.Zero);
+
+ if (double.IsNaN(res3[0]) || double.IsNaN(res4[0]))
+ {
+ return 0;
+ }
+ }
+
+ return 100;
+ }
+}
diff --git a/src/tests/JIT/Regression/JitBlue/ImageSharp_2117/ImageSharp_2117.csproj b/src/tests/JIT/Regression/JitBlue/ImageSharp_2117/ImageSharp_2117.csproj
new file mode 100644
index 00000000000000..e7284d26ab2f18
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/ImageSharp_2117/ImageSharp_2117.csproj
@@ -0,0 +1,13 @@
+
+
+ Exe
+ True
+
+
+ None
+ True
+
+
+
+
+