From e8872a428a6b12d20f9f10e7c86fda8c7aad22c7 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 24 Dec 2020 12:00:32 -0800 Subject: [PATCH 01/20] Implement managed side of CLong/CULong/NFloat. --- .../System.Private.CoreLib.Shared.projitems | 3 ++ .../System/Runtime/InteropServices/CLong.cs | 37 +++++++++++++++++++ .../System/Runtime/InteropServices/CULong.cs | 37 +++++++++++++++++++ .../System/Runtime/InteropServices/NFloat.cs | 36 ++++++++++++++++++ .../ref/System.Runtime.InteropServices.cs | 32 ++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs 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 dafa471e67f9c..0d30085debebc 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 @@ -707,6 +707,7 @@ + @@ -735,6 +736,7 @@ + @@ -769,6 +771,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs new file mode 100644 index 0000000000000..80b74549d3b9f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.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. + +#pragma warning disable SA1121 // We use our own aliases since they differ per platform +#if TARGET_WINDOWS +using NativeType = System.Int32; +#else +using NativeType = System.IntPtr; +#endif + +namespace System.Runtime.InteropServices +{ + [CLSCompliant(false)] + public readonly struct CLong : IEquatable + { + private readonly NativeType _value; + + public CLong(int value) + { + _value = value; + } + public CLong(nint value) + { + _value = (NativeType)value; + } + + public nint Value => _value; + + public override bool Equals(object? o) => o is CLong other && Equals(other); + + public bool Equals(CLong other) => _value == other._value; + + public override int GetHashCode() => _value.GetHashCode(); + + public override string ToString() => _value.ToString(); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs new file mode 100644 index 0000000000000..d51833f34c5b2 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.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. + +#pragma warning disable SA1121 // We use our own aliases since they differ per platform +#if TARGET_WINDOWS +using NativeType = System.UInt32; +#else +using NativeType = System.IntPtr; +#endif + +namespace System.Runtime.InteropServices +{ + [CLSCompliant(false)] + public readonly struct CULong : IEquatable + { + private readonly NativeType _value; + + public CULong(uint value) + { + _value = value; + } + public CULong(nuint value) + { + _value = (NativeType)value; + } + + public nuint Value => _value; + + public override bool Equals(object? o) => o is CULong other && Equals(other); + + public bool Equals(CULong other) => _value == other._value; + + public override int GetHashCode() => _value.GetHashCode(); + + public override string ToString() => _value.ToString(); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs new file mode 100644 index 0000000000000..f9476b6f90307 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma warning disable SA1121 // We use our own aliases since they differ per platform +#if TARGET_32BIT +using NativeType = System.Single; +#else +using NativeType = System.Double; +#endif + +namespace System.Runtime.InteropServices +{ + public readonly struct NFloat : IEquatable + { + private readonly NativeType _value; + + public NFloat(float value) + { + _value = value; + } + public NFloat(double value) + { + _value = (NativeType)value; + } + + public double Value => _value; + + public override bool Equals(object? o) => o is NFloat other && Equals(other); + + public bool Equals(NFloat other) => _value == other._value; + + public override int GetHashCode() => _value.GetHashCode(); + + public override string ToString() => _value.ToString(); + } +} diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 9bbb8e80f31da..eaf0081f8ec2a 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -156,6 +156,17 @@ public enum ClassInterfaceType [System.ObsoleteAttribute("Support for IDispatch may be unavailable in future releases.")] AutoDual = 2, } + [System.CLSCompliantAttribute(false)] + public readonly struct CLong : IEquatable + { + public CLong(int value) { } + public CLong(nint value) { } + public nint Value { get { throw null; } } + public override bool Equals(object? o) { throw null; } + public bool Equals(CLong other) { throw null; } + public override int GetHashCode() { throw null; } + public override string ToString() { throw null; } + } [System.AttributeUsageAttribute(System.AttributeTargets.Interface, Inherited=false)] public sealed partial class CoClassAttribute : System.Attribute { @@ -278,6 +289,17 @@ public sealed partial class ComUnregisterFunctionAttribute : System.Attribute { public ComUnregisterFunctionAttribute() { } } + [System.CLSCompliantAttribute(false)] + public readonly struct CULong : IEquatable + { + public CULong(uint value) { } + public CULong(nuint value) { } + public nuint Value { get { throw null; } } + public override bool Equals(object? o) { throw null; } + public bool Equals(CULong other) { throw null; } + public override int GetHashCode() { throw null; } + public override string ToString() { throw null; } + } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("CurrencyWrapper and support for marshalling to the VARIANT type may be unavailable in future releases.")] public sealed partial class CurrencyWrapper @@ -732,6 +754,16 @@ public static void SetDllImportResolver(System.Reflection.Assembly assembly, Sys public static bool TryLoad(string libraryPath, out System.IntPtr handle) { throw null; } public static bool TryLoad(string libraryName, System.Reflection.Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath, out System.IntPtr handle) { throw null; } } + public readonly struct NFloat : IEquatable + { + public NFloat(float value) { } + public NFloat(double value) { } + public double Value { get { throw null; } } + public override bool Equals(object? o) { throw null; } + public bool Equals(NFloat other) { throw null; } + public override int GetHashCode() { throw null; } + public override string ToString() { throw null; } + } [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, Inherited=false)] public sealed partial class OptionalAttribute : System.Attribute { From 3b7693ba558b0ba5a453b81644928f5426bc7d60 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 24 Dec 2020 16:15:06 -0800 Subject: [PATCH 02/20] Make CLong, CULong, and NFloat intrinsically handled correctly by the JIT. --- src/coreclr/jit/compiler.cpp | 21 +++++++++-- src/coreclr/jit/compiler.h | 35 +++++++++++-------- .../System/Runtime/InteropServices/CLong.cs | 1 + .../System/Runtime/InteropServices/CULong.cs | 1 + .../System/Runtime/InteropServices/NFloat.cs | 1 + 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 171bebb45e72b..383ab7129a82d 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -560,6 +560,23 @@ bool Compiler::isTrivialPointerSizedStruct(CORINFO_CLASS_HANDLE clsHnd) const } #endif // TARGET_X86 +bool Compiler::isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd) +{ + if (!isIntrinsicType(clsHnd)) + { + return false; + } + const char* namespaceName = nullptr; + const char* typeName = getClassNameFromMetadata(clsHnd, &namespaceName); + + if (strcmp(namespaceName, "System.Runtime.InteropServices") != 0) + { + return false; + } + + return strcmp(typeName, "CLong") == 0 || strcmp(typeName, "CULong") == 0 || strcmp(typeName, "NFloat") == 0; +} + //----------------------------------------------------------------------------- // getPrimitiveTypeForStruct: // Get the "primitive" type that is is used for a struct @@ -1013,14 +1030,14 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, } } #elif UNIX_X86_ABI - if (callConv != CorInfoCallConvExtension::Managed) + if (callConv != CorInfoCallConvExtension::Managed && !isNativePrimitiveStructType(clsHnd)) { canReturnInRegister = false; howToReturnStruct = SPK_ByReference; useType = TYP_UNKNOWN; } #elif defined(TARGET_WINDOWS) && !defined(TARGET_ARM) - if (callConvIsInstanceMethodCallConv(callConv)) + if (callConvIsInstanceMethodCallConv(callConv) && !isNativePrimitiveStructType(clsHnd)) { canReturnInRegister = false; howToReturnStruct = SPK_ByReference; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 67c6e0e582e0b..930224abbe980 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5035,6 +5035,11 @@ class Compiler // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types var_types getJitGCType(BYTE gcType); + + // Returns true if the provided type should be treated as a primitive type + // for the unmanaged calling conventions. + bool isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd); + enum structPassingKind { SPK_Unknown, // Invalid value, never returned @@ -8028,6 +8033,21 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif } + bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd) + { + return info.compCompHnd->isIntrinsicType(clsHnd); + } + + const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName) + { + return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName); + } + + CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) + { + return info.compCompHnd->getTypeInstantiationArgument(cls, index); + } + #ifdef FEATURE_SIMD // Should we support SIMD intrinsics? @@ -8246,21 +8266,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX return false; } - bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd) - { - return info.compCompHnd->isIntrinsicType(clsHnd); - } - - const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName) - { - return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName); - } - - CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) - { - return info.compCompHnd->getTypeInstantiationArgument(cls, index); - } - bool isSIMDClass(typeInfo* pTypeInfo) { return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass()); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs index 80b74549d3b9f..339675e463f2e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs @@ -11,6 +11,7 @@ namespace System.Runtime.InteropServices { [CLSCompliant(false)] + [Intrinsic] public readonly struct CLong : IEquatable { private readonly NativeType _value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs index d51833f34c5b2..9c0da0bac584c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs @@ -11,6 +11,7 @@ namespace System.Runtime.InteropServices { [CLSCompliant(false)] + [Intrinsic] public readonly struct CULong : IEquatable { private readonly NativeType _value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index f9476b6f90307..b876d113ec40c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -10,6 +10,7 @@ namespace System.Runtime.InteropServices { + [Intrinsic] public readonly struct NFloat : IEquatable { private readonly NativeType _value; From e598892240796cc3c645b47b40020a80bcf27cac Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 25 Dec 2020 11:45:53 -0800 Subject: [PATCH 03/20] Add framework tests for CLong, CULong, and NFloat. --- .../TestUtilities/System/PlatformDetection.cs | 1 + .../System/Runtime/InteropServices/CLong.cs | 4 +- .../System/Runtime/InteropServices/CULong.cs | 4 +- .../System/Runtime/InteropServices/NFloat.cs | 4 +- .../System.Runtime.InteropServices.sln | 129 +++++++++--------- ...ystem.Runtime.InteropServices.Tests.csproj | 3 + .../Runtime/InteropServices/CLongTests.cs | 87 ++++++++++++ .../Runtime/InteropServices/CULongTests.cs | 82 +++++++++++ .../Runtime/InteropServices/NFloatTests.cs | 82 +++++++++++ 9 files changed, 332 insertions(+), 64 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index b4520cc674845..53b02129328bf 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -43,6 +43,7 @@ public static partial class PlatformDetection public static bool IsArgIteratorSupported => IsMonoRuntime || (IsWindows && IsNotArmProcess); public static bool IsArgIteratorNotSupported => !IsArgIteratorSupported; public static bool Is32BitProcess => IntPtr.Size == 4; + public static bool Is64BitProcess => IntPtr.Size == 8; public static bool IsNotWindows => !IsWindows; public static bool IsThreadingSupported => !IsBrowser; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs index 339675e463f2e..b58cc663a4c9c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + #pragma warning disable SA1121 // We use our own aliases since they differ per platform #if TARGET_WINDOWS using NativeType = System.Int32; @@ -22,7 +24,7 @@ public CLong(int value) } public CLong(nint value) { - _value = (NativeType)value; + _value = checked((NativeType)value); } public nint Value => _value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs index 9c0da0bac584c..f9f2a8d2abb4e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + #pragma warning disable SA1121 // We use our own aliases since they differ per platform #if TARGET_WINDOWS using NativeType = System.UInt32; @@ -22,7 +24,7 @@ public CULong(uint value) } public CULong(nuint value) { - _value = (NativeType)value; + _value = checked((NativeType)value); } public nuint Value => _value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index b876d113ec40c..b52fe8213dcc6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + #pragma warning disable SA1121 // We use our own aliases since they differ per platform #if TARGET_32BIT using NativeType = System.Single; @@ -21,7 +23,7 @@ public NFloat(float value) } public NFloat(double value) { - _value = (NativeType)value; + _value = checked((NativeType)value); } public double Value => _value; diff --git a/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln b/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln index 7400e16352b4f..5c2bde08c0163 100644 --- a/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln +++ b/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30802.240 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj", "{94B59BA0-491F-4B59-ADFF-A057EC3EC835}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}" @@ -7,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Win32.Registry", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{5BB5F99F-1052-4EB4-B12E-7863805661F3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\src\System.Runtime.CompilerServices.Unsafe.ilproj", "{23735A0B-AB51-4C1D-BD88-5240D672DD33}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\src\System.Runtime.CompilerServices.Unsafe.ilproj", "{04BA3E3C-6979-4792-B19E-C797AD607F42}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices", "ref\System.Runtime.InteropServices.csproj", "{8671F164-F78C-44FA-93B7-A310F67890FE}" EndProject @@ -26,30 +30,27 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{E7481FAF-728B-448D-9A38-88B40E3C400E}" EndProject Global - GlobalSection(NestedProjects) = preSolution - {94B59BA0-491F-4B59-ADFF-A057EC3EC835} = {F66D19A6-4D11-45EC-B73F-7F4E4F8DB76B} - {23735A0B-AB51-4C1D-BD88-5240D672DD33} = {F66D19A6-4D11-45EC-B73F-7F4E4F8DB76B} - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1} = {F66D19A6-4D11-45EC-B73F-7F4E4F8DB76B} - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA} = {451A41C1-B1BC-49DE-8F3F-26F2D8BF841A} - {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664} = {451A41C1-B1BC-49DE-8F3F-26F2D8BF841A} - {EB306595-C964-474F-AFEE-803C886E4B8B} = {E7481FAF-728B-448D-9A38-88B40E3C400E} - {5BB5F99F-1052-4EB4-B12E-7863805661F3} = {E7481FAF-728B-448D-9A38-88B40E3C400E} - {8671F164-F78C-44FA-93B7-A310F67890FE} = {E7481FAF-728B-448D-9A38-88B40E3C400E} - {B8C46FFD-86D0-4C84-97A5-60DDF29ED543} = {E7481FAF-728B-448D-9A38-88B40E3C400E} - {92B81157-BB47-4A19-9229-23AE9B126DAA} = {E7481FAF-728B-448D-9A38-88B40E3C400E} + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{94b59ba0-491f-4b59-adff-a057ec3ec835}*SharedItemsImports = 5 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|Any CPU = Checked|Any CPU + Checked|x64 = Checked|x64 + Checked|x86 = Checked|x86 Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 - Checked|Any CPU = Checked|Any CPU - Checked|x64 = Checked|x64 - Checked|x86 = Checked|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.ActiveCfg = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.Build.0 = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.ActiveCfg = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.Build.0 = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.ActiveCfg = Checked|x86 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.Build.0 = Checked|x86 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Debug|Any CPU.ActiveCfg = Debug|x64 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Debug|Any CPU.Build.0 = Debug|x64 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Debug|x64.ActiveCfg = Debug|x64 @@ -62,12 +63,9 @@ Global {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Release|x64.Build.0 = Release|x64 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Release|x86.ActiveCfg = Release|x86 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Release|x86.Build.0 = Release|x86 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.ActiveCfg = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.Build.0 = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.ActiveCfg = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.Build.0 = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.ActiveCfg = Checked|x86 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.Build.0 = Checked|x86 + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x64.ActiveCfg = Debug|Any CPU + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x86.ActiveCfg = Debug|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Debug|Any CPU.Build.0 = Debug|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -80,9 +78,9 @@ Global {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Release|x64.Build.0 = Release|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Release|x86.ActiveCfg = Release|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Release|x86.Build.0 = Release|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x64.ActiveCfg = Debug|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x86.ActiveCfg = Debug|Any CPU + {EB306595-C964-474F-AFEE-803C886E4B8B}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {EB306595-C964-474F-AFEE-803C886E4B8B}.Checked|x64.ActiveCfg = Debug|Any CPU + {EB306595-C964-474F-AFEE-803C886E4B8B}.Checked|x86.ActiveCfg = Debug|Any CPU {EB306595-C964-474F-AFEE-803C886E4B8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EB306595-C964-474F-AFEE-803C886E4B8B}.Debug|Any CPU.Build.0 = Debug|Any CPU {EB306595-C964-474F-AFEE-803C886E4B8B}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -95,9 +93,9 @@ Global {EB306595-C964-474F-AFEE-803C886E4B8B}.Release|x64.Build.0 = Release|Any CPU {EB306595-C964-474F-AFEE-803C886E4B8B}.Release|x86.ActiveCfg = Release|Any CPU {EB306595-C964-474F-AFEE-803C886E4B8B}.Release|x86.Build.0 = Release|Any CPU - {EB306595-C964-474F-AFEE-803C886E4B8B}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {EB306595-C964-474F-AFEE-803C886E4B8B}.Checked|x64.ActiveCfg = Debug|Any CPU - {EB306595-C964-474F-AFEE-803C886E4B8B}.Checked|x86.ActiveCfg = Debug|Any CPU + {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Checked|x64.ActiveCfg = Debug|Any CPU + {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Checked|x86.ActiveCfg = Debug|Any CPU {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Debug|Any CPU.Build.0 = Debug|Any CPU {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -110,24 +108,24 @@ Global {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Release|x64.Build.0 = Release|Any CPU {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Release|x86.ActiveCfg = Release|Any CPU {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Release|x86.Build.0 = Release|Any CPU - {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Checked|x64.ActiveCfg = Debug|Any CPU - {5BB5F99F-1052-4EB4-B12E-7863805661F3}.Checked|x86.ActiveCfg = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Debug|Any CPU.Build.0 = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Debug|x64.ActiveCfg = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Debug|x64.Build.0 = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Debug|x86.ActiveCfg = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Debug|x86.Build.0 = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Release|Any CPU.ActiveCfg = Release|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Release|Any CPU.Build.0 = Release|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Release|x64.ActiveCfg = Release|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Release|x64.Build.0 = Release|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Release|x86.ActiveCfg = Release|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Release|x86.Build.0 = Release|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Checked|x64.ActiveCfg = Debug|Any CPU - {23735A0B-AB51-4C1D-BD88-5240D672DD33}.Checked|x86.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Checked|x64.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Checked|x86.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|x64.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|x64.Build.0 = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|x86.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|x86.Build.0 = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|Any CPU.Build.0 = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|x64.ActiveCfg = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|x64.Build.0 = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|x86.ActiveCfg = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|x86.Build.0 = Release|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x64.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x86.ActiveCfg = Debug|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -140,9 +138,9 @@ Global {8671F164-F78C-44FA-93B7-A310F67890FE}.Release|x64.Build.0 = Release|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Release|x86.ActiveCfg = Release|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Release|x86.Build.0 = Release|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x64.ActiveCfg = Debug|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x86.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x64.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x86.ActiveCfg = Debug|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -155,9 +153,9 @@ Global {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Release|x64.Build.0 = Release|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Release|x86.ActiveCfg = Release|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Release|x86.Build.0 = Release|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x64.ActiveCfg = Debug|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x86.ActiveCfg = Debug|Any CPU + {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Checked|x64.ActiveCfg = Debug|Any CPU + {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Checked|x86.ActiveCfg = Debug|Any CPU {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Debug|Any CPU.Build.0 = Debug|Any CPU {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -170,9 +168,9 @@ Global {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Release|x64.Build.0 = Release|Any CPU {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Release|x86.ActiveCfg = Release|Any CPU {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Release|x86.Build.0 = Release|Any CPU - {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Checked|x64.ActiveCfg = Debug|Any CPU - {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664}.Checked|x86.ActiveCfg = Debug|Any CPU + {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Checked|x64.ActiveCfg = Debug|Any CPU + {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Checked|x86.ActiveCfg = Debug|Any CPU {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Debug|Any CPU.Build.0 = Debug|Any CPU {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -185,9 +183,9 @@ Global {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Release|x64.Build.0 = Release|Any CPU {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Release|x86.ActiveCfg = Release|Any CPU {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Release|x86.Build.0 = Release|Any CPU - {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Checked|x64.ActiveCfg = Debug|Any CPU - {B8C46FFD-86D0-4C84-97A5-60DDF29ED543}.Checked|x86.ActiveCfg = Debug|Any CPU + {92B81157-BB47-4A19-9229-23AE9B126DAA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {92B81157-BB47-4A19-9229-23AE9B126DAA}.Checked|x64.ActiveCfg = Debug|Any CPU + {92B81157-BB47-4A19-9229-23AE9B126DAA}.Checked|x86.ActiveCfg = Debug|Any CPU {92B81157-BB47-4A19-9229-23AE9B126DAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {92B81157-BB47-4A19-9229-23AE9B126DAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {92B81157-BB47-4A19-9229-23AE9B126DAA}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -200,13 +198,22 @@ Global {92B81157-BB47-4A19-9229-23AE9B126DAA}.Release|x64.Build.0 = Release|Any CPU {92B81157-BB47-4A19-9229-23AE9B126DAA}.Release|x86.ActiveCfg = Release|Any CPU {92B81157-BB47-4A19-9229-23AE9B126DAA}.Release|x86.Build.0 = Release|Any CPU - {92B81157-BB47-4A19-9229-23AE9B126DAA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {92B81157-BB47-4A19-9229-23AE9B126DAA}.Checked|x64.ActiveCfg = Debug|Any CPU - {92B81157-BB47-4A19-9229-23AE9B126DAA}.Checked|x86.ActiveCfg = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {94B59BA0-491F-4B59-ADFF-A057EC3EC835} = {F66D19A6-4D11-45EC-B73F-7F4E4F8DB76B} + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA} = {451A41C1-B1BC-49DE-8F3F-26F2D8BF841A} + {EB306595-C964-474F-AFEE-803C886E4B8B} = {E7481FAF-728B-448D-9A38-88B40E3C400E} + {5BB5F99F-1052-4EB4-B12E-7863805661F3} = {E7481FAF-728B-448D-9A38-88B40E3C400E} + {04BA3E3C-6979-4792-B19E-C797AD607F42} = {F66D19A6-4D11-45EC-B73F-7F4E4F8DB76B} + {8671F164-F78C-44FA-93B7-A310F67890FE} = {E7481FAF-728B-448D-9A38-88B40E3C400E} + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1} = {F66D19A6-4D11-45EC-B73F-7F4E4F8DB76B} + {E249BD6A-85DB-4CE4-BD82-8D67EBAC5664} = {451A41C1-B1BC-49DE-8F3F-26F2D8BF841A} + {B8C46FFD-86D0-4C84-97A5-60DDF29ED543} = {E7481FAF-728B-448D-9A38-88B40E3C400E} + {92B81157-BB47-4A19-9229-23AE9B126DAA} = {E7481FAF-728B-448D-9A38-88B40E3C400E} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D4031401-FEB5-4CCF-91C1-38F5646B2BFD} EndGlobalSection diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj index 69396c3d0fb95..29c38f3766bfc 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj @@ -13,6 +13,9 @@ + + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs new file mode 100644 index 0000000000000..a385852ec0d09 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs @@ -0,0 +1,87 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Runtime.InteropServices.Tests +{ + public class CLongTests + { + private static unsafe bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; + private static unsafe bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; + + [Fact] + public void Ctor_Empty() + { + CLong value = new CLong(); + Assert.Equal(0, value.Value); + } + + [Fact] + public void Ctor_Int() + { + CLong value = new CLong(42); + Assert.Equal(42, value.Value); + } + + [Fact] + public void Ctor_NInt() + { + CLong value = new CLong((nint)42); + Assert.Equal(42, value.Value); + } + + [ConditionalFact(nameof(Has32BitStorage))] + public void Ctor_NInt_OutOfRange() + { + Assert.Throws(() => new CLong(unchecked(((nint)int.MaxValue) + 1))); + } + + [ConditionalFact(nameof(Has64BitStorage))] + public void Ctor_NInt_LargeValue() + { + nint largeValue = unchecked(((nint)int.MaxValue) + 1); + CLong value = new CLong(largeValue); + Assert.Equal(largeValue, value.Value); + } + + [Theory] + [InlineData(789, 789, true)] + [InlineData(789, -789, false)] + [InlineData(789, 0, false)] + [InlineData(0, 0, true)] + [InlineData(-789, -789, true)] + [InlineData(-789, 789, false)] + [InlineData(789, null, false)] + [InlineData(789, "789", false)] + [InlineData(789, (long)789, false)] + public static void EqualsTest(int i1, object obj, bool expected) + { + if (obj is int i) + { + CLong i2 = new CLong(i); + Assert.Equal(expected, new CLong(i1).Equals(i2)); + Assert.Equal(expected, new CLong(i1).GetHashCode().Equals(i2.GetHashCode())); + } + Assert.Equal(expected, new CLong(i1).Equals(obj)); + } + + [Theory] + [InlineData(int.MinValue, "-2147483648")] + [InlineData(-4567, "-4567")] + [InlineData(0, "0")] + [InlineData(4567, "4567")] + [InlineData(int.MaxValue, "2147483647")] + public static void ToStringTest(int value, string expected) + { + CLong clong = new CLong(value); + + Assert.Equal(expected, clong.ToString()); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs new file mode 100644 index 0000000000000..72281b7666dd9 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs @@ -0,0 +1,82 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Runtime.InteropServices.Tests +{ + public class CULongTests + { + private static unsafe bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; + private static unsafe bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; + + [Fact] + public void Ctor_Empty() + { + CULong value = new CULong(); + Assert.Equal(0u, value.Value); + } + + [Fact] + public void Ctor_Int() + { + CULong value = new CULong(42u); + Assert.Equal(42u, value.Value); + } + + [Fact] + public void Ctor_NInt() + { + CULong value = new CULong((nuint)42); + Assert.Equal(42u, value.Value); + } + + [ConditionalFact(nameof(Has32BitStorage))] + public void Ctor_NInt_OutOfRange() + { + Assert.Throws(() => new CULong(unchecked(((nuint)uint.MaxValue) + 1))); + } + + [ConditionalFact(nameof(Has64BitStorage))] + public void Ctor_NInt_LargeValue() + { + nuint largeValue = unchecked(((nuint)uint.MaxValue) + 1); + CULong value = new CULong(largeValue); + Assert.Equal(largeValue, value.Value); + } + + [Theory] + [InlineData(789, 789, true)] + [InlineData(789, 0, false)] + [InlineData(0, 0, true)] + [InlineData(789, null, false)] + [InlineData(789, "789", false)] + [InlineData(789, (long)789, false)] + public static void EqualsTest(uint i1, object obj, bool expected) + { + if (obj is uint i) + { + CULong i2 = new CULong(i); + Assert.Equal(expected, new CULong(i1).Equals(i2)); + Assert.Equal(expected, new CULong(i1).GetHashCode().Equals(i2.GetHashCode())); + } + Assert.Equal(expected, new CULong(i1).Equals(obj)); + } + + [Theory] + [InlineData(0, "0")] + [InlineData(4567, "4567")] + [InlineData(uint.MaxValue, "4294967295")] + public static void ToStringTest(uint value, string expected) + { + CULong culong = new CULong(value); + + Assert.Equal(expected, culong.ToString()); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs new file mode 100644 index 0000000000000..74950fb6fdc2b --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -0,0 +1,82 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Runtime.InteropServices.Tests +{ + public class NFloatTests + { + [Fact] + public void Ctor_Empty() + { + NFloat value = new NFloat(); + Assert.Equal(0, value.Value); + } + + [Fact] + public void Ctor_Int() + { + NFloat value = new NFloat(42.0f); + Assert.Equal(42.0, value.Value); + } + + [Fact] + public void Ctor_NInt() + { + NFloat value = new NFloat(42.0); + Assert.Equal(42.0, value.Value); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + public void Ctor_NInt_OutOfRange() + { + Assert.Throws(() => new NFloat(double.MaxValue)); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + public void Ctor_NInt_LargeValue() + { + NFloat value = new NFloat(double.MaxValue); + Assert.Equal(double.MaxValue, value.Value); + } + + [Theory] + [InlineData(789.0f, 789.0f, true)] + [InlineData(789.0f, -789.0f, false)] + [InlineData(789.0f, 0.0f, false)] + [InlineData(float.NaN, float.NaN, true)] + [InlineData(789.0f, 789.0, false)] + [InlineData(789.0f, "789", false)] + public static void EqualsTest(float f1, object obj, bool expected) + { + if (obj is float f) + { + NFloat f2 = new NFloat(f); + Assert.Equal(expected, new NFloat(f1).Equals(f2)); + Assert.Equal(expected, new NFloat(f1).GetHashCode().Equals(f2.GetHashCode())); + } + Assert.Equal(expected, new NFloat(f1).Equals(obj)); + } + + [Theory] + [InlineData(-4567.0f, "-4567")] + [InlineData(-4567.89101f, "-4567.891")] + [InlineData(0.0f, "0")] + [InlineData(4567.0f, "4567")] + [InlineData(4567.89101f, "4567.891")] + + [InlineData(float.NaN, "NaN")] + public static void ToStringTest(float value, string expected) + { + NFloat nfloat = new NFloat(value); + + Assert.Equal(expected, nfloat.ToString()); + } + } +} From c9d8d138eba13b41beee1f00f9b90258b7d32b0e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 25 Dec 2020 12:22:38 -0800 Subject: [PATCH 04/20] Add interop test of CLong to validate calling convention semantics. --- .../Miscellaneous/ThisCall/ThisCallNative.cpp | 10 ++++ .../Miscellaneous/ThisCall/ThisCallTest.cs | 54 +++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallNative.cpp b/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallNative.cpp index cf2569fb75386..6c70fc5f6de98 100644 --- a/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallNative.cpp +++ b/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallNative.cpp @@ -57,6 +57,11 @@ class C { return dummy; } + + virtual long GetWidthAsLong() + { + return (long)width; + } }; @@ -84,3 +89,8 @@ extern "C" DLL_EXPORT E STDMETHODCALLTYPE GetEFromManaged(C* c) { return c->GetE(); } + +extern "C" DLL_EXPORT long STDMETHODCALLTYPE GetWidthAsLongFromManaged(C* c) +{ + return c->GetWidthAsLong(); +} diff --git a/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs b/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs index 31719e8d7aed8..0509ffe568318 100644 --- a/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs +++ b/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs @@ -1,12 +1,12 @@ // 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; using System; using System.Reflection; using System.Text; using TestLibrary; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; unsafe class ThisCallNative { @@ -18,6 +18,7 @@ public struct VtableLayout public IntPtr getWidth; public IntPtr getHeightAsInt; public IntPtr getE; + public IntPtr getWidthAsLong; } public VtableLayout* vtable; @@ -57,6 +58,9 @@ public enum E : uint [UnmanagedFunctionPointer(CallingConvention.ThisCall)] public delegate E GetEFn(C* c); + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate CLong GetWidthAsLongFn(C* c); + [DllImport(nameof(ThisCallNative))] public static extern C* CreateInstanceOfC(float width, float height); @@ -68,6 +72,8 @@ public enum E : uint public static extern IntWrapper GetHeightAsIntFromManaged(C* c); [DllImport(nameof(ThisCallNative))] public static extern E GetEFromManaged(C* c); + [DllImport(nameof(ThisCallNative))] + public static extern CLong GetWidthAsLongFromManaged(C* c); } unsafe class ThisCallTest @@ -83,14 +89,17 @@ public static int Main(string[] args) Test4ByteHFA(instance); Test4ByteNonHFA(instance); TestEnum(instance); + TestCLong(instance); Test8ByteHFAReverse(); Test4ByteHFAReverse(); Test4ByteNonHFAReverse(); TestEnumReverse(); + TestCLongReverse(); Test8ByteHFAUnmanagedCallersOnly(); Test4ByteHFAUnmanagedCallersOnly(); Test4ByteNonHFAUnmanagedCallersOnly(); TestEnumUnmanagedCallersOnly(); + TestCLongUnmanagedCallersOnly(); } catch (System.Exception ex) { @@ -137,15 +146,24 @@ private static void TestEnum(ThisCallNative.C* instance) Assert.AreEqual(instance->dummy, result); } + private static void TestCLong(ThisCallNative.C* instance) + { + ThisCallNative.GetWidthAsLongFn callback = Marshal.GetDelegateForFunctionPointer(instance->vtable->getWidthAsLong); + + CLong result = callback(instance); + + Assert.AreEqual((nint)instance->width, result.Value); + } + private static void Test8ByteHFAReverse() { ThisCallNative.C c = CreateCWithManagedVTable(2.0f, 3.0f); ThisCallNative.SizeF result = ThisCallNative.GetSizeFromManaged(&c); - + Assert.AreEqual(c.width, result.width); Assert.AreEqual(c.height, result.height); } - + private static void Test4ByteHFAReverse() { ThisCallNative.C c = CreateCWithManagedVTable(2.0f, 3.0f); @@ -169,15 +187,24 @@ private static void TestEnumReverse() Assert.AreEqual(c.dummy, result); } + + private static void TestCLongReverse() + { + ThisCallNative.C c = CreateCWithManagedVTable(2.0f, 3.0f); + CLong result = ThisCallNative.GetWidthAsLongFromManaged(&c); + + Assert.AreEqual((nint)c.width, result.Value); + } + private static void Test8ByteHFAUnmanagedCallersOnly() { ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); ThisCallNative.SizeF result = ThisCallNative.GetSizeFromManaged(&c); - + Assert.AreEqual(c.width, result.width); Assert.AreEqual(c.height, result.height); } - + private static void Test4ByteHFAUnmanagedCallersOnly() { ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); @@ -202,6 +229,14 @@ private static void TestEnumUnmanagedCallersOnly() Assert.AreEqual(c.dummy, result); } + private static void TestCLongUnmanagedCallersOnly() + { + ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); + CLong result = ThisCallNative.GetWidthAsLongFromManaged(&c); + + Assert.AreEqual((nint)c.width, result.Value); + } + private static ThisCallNative.C CreateCWithManagedVTable(float width, float height) { return new ThisCallNative.C @@ -241,6 +276,8 @@ private static ThisCallNative.C.VtableLayout* ManagedVtable (ThisCallNative.GetHeightAsIntFn)((ThisCallNative.C* c) => new ThisCallNative.IntWrapper { i = (int)c->height} )); managedVtable->getE = Marshal.GetFunctionPointerForDelegate( (ThisCallNative.GetEFn)((ThisCallNative.C* c) => c->dummy )); + managedVtable->getWidthAsLong = Marshal.GetFunctionPointerForDelegate( + (ThisCallNative.GetWidthAsLongFn)((ThisCallNative.C* c) => new CLong((nint)c->width))); } return managedVtable; } @@ -259,6 +296,7 @@ private static ThisCallNative.C.VtableLayout* UnmanagedCallersOnlyVtable unmanagedCallersOnlyVtable->getWidth = (IntPtr)(delegate* unmanaged[Thiscall])&GetWidth; unmanagedCallersOnlyVtable->getHeightAsInt = (IntPtr)(delegate* unmanaged[Thiscall])&GetHeightAsInt; unmanagedCallersOnlyVtable->getE = (IntPtr)(delegate* unmanaged[Thiscall])&GetE; + unmanagedCallersOnlyVtable->getWidthAsLong = (IntPtr)(delegate* unmanaged[Thiscall])&GetWidthAsLong; } return unmanagedCallersOnlyVtable; } @@ -297,4 +335,10 @@ private static ThisCallNative.E GetE(ThisCallNative.C* c) { return c->dummy; } + + [UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvThiscall)})] + private static CLong GetWidthAsLong(ThisCallNative.C* c) + { + return new CLong((nint)c->width); + } } From 0aeaaf7716dc85b136a9cef2663683eb037fa2f3 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 25 Dec 2020 12:44:51 -0800 Subject: [PATCH 05/20] Update CULong.cs --- .../src/System/Runtime/InteropServices/CULong.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs index f9f2a8d2abb4e..d0c947b217f22 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs @@ -7,7 +7,7 @@ #if TARGET_WINDOWS using NativeType = System.UInt32; #else -using NativeType = System.IntPtr; +using NativeType = System.UIntPtr; #endif namespace System.Runtime.InteropServices From 2baa10dbbc4763face13613841a0da50b5291b78 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 25 Dec 2020 13:53:49 -0800 Subject: [PATCH 06/20] Fix implicit conversions. --- .../src/System/Runtime/InteropServices/CLong.cs | 2 +- .../src/System/Runtime/InteropServices/CULong.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs index b58cc663a4c9c..fc7205582a35c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs @@ -20,7 +20,7 @@ namespace System.Runtime.InteropServices public CLong(int value) { - _value = value; + _value = (NativeType)value; } public CLong(nint value) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs index f9f2a8d2abb4e..0c1eefa602511 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs @@ -20,7 +20,7 @@ namespace System.Runtime.InteropServices public CULong(uint value) { - _value = value; + _value = (NativeType)value; } public CULong(nuint value) { From d2da1d8bb4d938b06272d614da0d5c25401454f4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 4 Jan 2021 10:25:04 -0800 Subject: [PATCH 07/20] Fix overflow and equality test failures. --- .../src/System/Runtime/InteropServices/NFloat.cs | 8 +++++++- .../System/Runtime/InteropServices/CLongTests.cs | 16 +++++++++++----- .../Runtime/InteropServices/CULongTests.cs | 16 +++++++++++----- .../Runtime/InteropServices/NFloatTests.cs | 10 +++++++--- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index b52fe8213dcc6..4053d73d1955c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -23,7 +23,13 @@ public NFloat(float value) } public NFloat(double value) { - _value = checked((NativeType)value); +#if TARGET_32BIT + if (value > NativeType.MaxValue) + { + throw new OverflowException(); + } +#endif + _value = (NativeType)value; } public double Value => _value; diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs index a385852ec0d09..bf9f2afd0ee6c 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs @@ -12,8 +12,10 @@ namespace System.Runtime.InteropServices.Tests { public class CLongTests { - private static unsafe bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; - private static unsafe bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; + private static bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; + private static bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; + private static bool NativeIntConstructorCanOverflow => !PlatformDetection.Is32BitProcess && Has32BitStorage; + private static bool NativeIntConstructorCannotOverflow => !NativeIntConstructorCanOverflow; [Fact] public void Ctor_Empty() @@ -36,13 +38,13 @@ public void Ctor_NInt() Assert.Equal(42, value.Value); } - [ConditionalFact(nameof(Has32BitStorage))] + [ConditionalFact(nameof(NativeIntConstructorCanOverflow))] public void Ctor_NInt_OutOfRange() { Assert.Throws(() => new CLong(unchecked(((nint)int.MaxValue) + 1))); } - [ConditionalFact(nameof(Has64BitStorage))] + [ConditionalFact(nameof(NativeIntConstructorCannotOverflow))] public void Ctor_NInt_LargeValue() { nint largeValue = unchecked(((nint)int.MaxValue) + 1); @@ -65,10 +67,14 @@ public static void EqualsTest(int i1, object obj, bool expected) if (obj is int i) { CLong i2 = new CLong(i); + Assert.Equal(expected, new CLong(i1).Equals((object)i2)); Assert.Equal(expected, new CLong(i1).Equals(i2)); Assert.Equal(expected, new CLong(i1).GetHashCode().Equals(i2.GetHashCode())); } - Assert.Equal(expected, new CLong(i1).Equals(obj)); + else + { + Assert.Equal(expected, new CLong(i1).Equals(obj)); + } } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs index 72281b7666dd9..dcf0bffad6ea3 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs @@ -12,8 +12,10 @@ namespace System.Runtime.InteropServices.Tests { public class CULongTests { - private static unsafe bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; - private static unsafe bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; + private static bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; + private static bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; + private static bool NativeIntConstructorCanOverflow => !PlatformDetection.Is32BitProcess && Has32BitStorage; + private static bool NativeIntConstructorCannotOverflow => !NativeIntConstructorCanOverflow; [Fact] public void Ctor_Empty() @@ -36,13 +38,13 @@ public void Ctor_NInt() Assert.Equal(42u, value.Value); } - [ConditionalFact(nameof(Has32BitStorage))] + [ConditionalFact(nameof(NativeIntConstructorCanOverflow))] public void Ctor_NInt_OutOfRange() { Assert.Throws(() => new CULong(unchecked(((nuint)uint.MaxValue) + 1))); } - [ConditionalFact(nameof(Has64BitStorage))] + [ConditionalFact(nameof(NativeIntConstructorCannotOverflow))] public void Ctor_NInt_LargeValue() { nuint largeValue = unchecked(((nuint)uint.MaxValue) + 1); @@ -62,10 +64,14 @@ public static void EqualsTest(uint i1, object obj, bool expected) if (obj is uint i) { CULong i2 = new CULong(i); + Assert.Equal(expected, new CULong(i1).Equals((object)i2)); Assert.Equal(expected, new CULong(i1).Equals(i2)); Assert.Equal(expected, new CULong(i1).GetHashCode().Equals(i2.GetHashCode())); } - Assert.Equal(expected, new CULong(i1).Equals(obj)); + else + { + Assert.Equal(expected, new CULong(i1).Equals(obj)); + } } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index 74950fb6fdc2b..c9480c073d027 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -58,18 +58,22 @@ public static void EqualsTest(float f1, object obj, bool expected) if (obj is float f) { NFloat f2 = new NFloat(f); + Assert.Equal(expected, new NFloat(f1).Equals((object)f2)); Assert.Equal(expected, new NFloat(f1).Equals(f2)); Assert.Equal(expected, new NFloat(f1).GetHashCode().Equals(f2.GetHashCode())); } - Assert.Equal(expected, new NFloat(f1).Equals(obj)); + else + { + Assert.Equal(expected, new NFloat(f1).Equals(obj)); + } } [Theory] [InlineData(-4567.0f, "-4567")] - [InlineData(-4567.89101f, "-4567.891")] + [InlineData(-4567.89101f, "-4567.89111328125")] [InlineData(0.0f, "0")] [InlineData(4567.0f, "4567")] - [InlineData(4567.89101f, "4567.891")] + [InlineData(4567.89101f, "4567.89111328125")] [InlineData(float.NaN, "NaN")] public static void ToStringTest(float value, string expected) From f1410230dee31959f13383810056c0c38965c0ef Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 4 Jan 2021 10:43:39 -0800 Subject: [PATCH 08/20] Fix formatting. --- .../src/System/Runtime/InteropServices/CLong.cs | 1 + .../src/System/Runtime/InteropServices/CULong.cs | 1 + .../src/System/Runtime/InteropServices/NFloat.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs index fc7205582a35c..1af21c23204de 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs @@ -22,6 +22,7 @@ public CLong(int value) { _value = (NativeType)value; } + public CLong(nint value) { _value = checked((NativeType)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs index df0bf304d9e5b..574e771b08f93 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs @@ -22,6 +22,7 @@ public CULong(uint value) { _value = (NativeType)value; } + public CULong(nuint value) { _value = checked((NativeType)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index 4053d73d1955c..bf0f72f2d5c94 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -21,6 +21,7 @@ public NFloat(float value) { _value = value; } + public NFloat(double value) { #if TARGET_32BIT From e587cfc4268690ad0e5303cb204355f726fc05aa Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 4 Jan 2021 10:48:06 -0800 Subject: [PATCH 09/20] Fix formatting and add function header. --- src/coreclr/jit/compiler.cpp | 12 ++++++++++++ src/coreclr/jit/compiler.h | 1 - 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 383ab7129a82d..07472528746c8 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -560,6 +560,18 @@ bool Compiler::isTrivialPointerSizedStruct(CORINFO_CLASS_HANDLE clsHnd) const } #endif // TARGET_X86 +//--------------------------------------------------------------------------- +// isNativePrimitiveStructType: +// Check if the given struct type is an intrinsic type that should be treated as though +// it is not a struct at the unmanaged ABI boundary. +// +// Arguments: +// clsHnd - the handle for the struct type. +// +// Return Value: +// true if the given struct type should be treated as a primitive for unmanaged calls, +// false otherwise. +// bool Compiler::isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd) { if (!isIntrinsicType(clsHnd)) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 930224abbe980..41017209efdd5 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5035,7 +5035,6 @@ class Compiler // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types var_types getJitGCType(BYTE gcType); - // Returns true if the provided type should be treated as a primitive type // for the unmanaged calling conventions. bool isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd); From 5b9d7a313d318e3b9f81f86d74d9a20061282d6a Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 4 Jan 2021 11:19:03 -0800 Subject: [PATCH 10/20] Add doc comments. --- .../System/Runtime/InteropServices/CLong.cs | 37 ++++++++++++++++++ .../System/Runtime/InteropServices/CULong.cs | 37 ++++++++++++++++++ .../System/Runtime/InteropServices/NFloat.cs | 38 ++++++++++++++++++- 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs index 1af21c23204de..3d4e868c6b766 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CLong.cs @@ -12,30 +12,67 @@ namespace System.Runtime.InteropServices { + /// + /// is an immutable value type that represents the long type in C and C++. + /// It is meant to be used as an exchange type at the managed/unmanaged boundary to accurately represent + /// in managed code unmanaged APIs that use the long type. + /// This type has 32-bits of storage on all Windows platforms and 32-bit Unix-based platforms. + /// It has 64-bits of storage on 64-bit Unix platforms. + /// [CLSCompliant(false)] [Intrinsic] public readonly struct CLong : IEquatable { private readonly NativeType _value; + /// + /// Constructs an instance from a 32-bit integer. + /// + /// The integer vaule. public CLong(int value) { _value = (NativeType)value; } + /// + /// Constructs an instance from a native sized integer. + /// + /// The integer vaule. + /// is outside the range of the underlying storage type. public CLong(nint value) { _value = checked((NativeType)value); } + /// + /// The underlying integer value of this instance. + /// public nint Value => _value; + /// + /// Returns a value indicating whether this instance is equal to a specified object. + /// + /// An object to compare with this instance. + /// true if is an instance of and equals the value of this instance; otherwise, false. public override bool Equals(object? o) => o is CLong other && Equals(other); + /// + /// Returns a value indicating whether this instance is equal to a specified value. + /// + /// A value to compare to this instance. + /// true if has the same value as this instance; otherwise, false. public bool Equals(CLong other) => _value == other._value; + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. public override int GetHashCode() => _value.GetHashCode(); + /// + /// Converts the numeric value of this instance to its equivalent string representation. + /// + /// The string representation of the value of this instance, consisting of a negative sign if the value is negative, and a sequence of digits ranging from 0 to 9 with no leading zeroes. public override string ToString() => _value.ToString(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs index 574e771b08f93..8ad64727e92bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CULong.cs @@ -12,30 +12,67 @@ namespace System.Runtime.InteropServices { + /// + /// is an immutable value type that represents the unsigned long type in C and C++. + /// It is meant to be used as an exchange type at the managed/unmanaged boundary to accurately represent + /// in managed code unmanaged APIs that use the unsigned long type. + /// This type has 32-bits of storage on all Windows platforms and 32-bit Unix-based platforms. + /// It has 64-bits of storage on 64-bit Unix platforms. + /// [CLSCompliant(false)] [Intrinsic] public readonly struct CULong : IEquatable { private readonly NativeType _value; + /// + /// Constructs an instance from a 32-bit unsigned integer. + /// + /// The integer vaule. public CULong(uint value) { _value = (NativeType)value; } + /// + /// Constructs an instance from a native sized unsigned integer. + /// + /// The integer vaule. + /// is outside the range of the underlying storage type. public CULong(nuint value) { _value = checked((NativeType)value); } + /// + /// The underlying integer value of this instance. + /// public nuint Value => _value; + /// + /// Returns a value indicating whether this instance is equal to a specified object. + /// + /// An object to compare with this instance. + /// true if is an instance of and equals the value of this instance; otherwise, false. public override bool Equals(object? o) => o is CULong other && Equals(other); + /// + /// Returns a value indicating whether this instance is equal to a specified value. + /// + /// A value to compare to this instance. + /// true if has the same value as this instance; otherwise, false. public bool Equals(CULong other) => _value == other._value; + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. public override int GetHashCode() => _value.GetHashCode(); + /// + /// Converts the numeric value of this instance to its equivalent string representation. + /// + /// The string representation of the value of this instance, consisting of a sequence of digits ranging from 0 to 9 with no leading zeroes. public override string ToString() => _value.ToString(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index bf0f72f2d5c94..1fe0a5a62727f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -12,20 +12,35 @@ namespace System.Runtime.InteropServices { + /// + /// is an immutable value type that represents a floating type that has the same size + /// as the native integer size. + /// It is meant to be used as an exchange type at the managed/unmanaged boundary to accurately represent + /// in managed code unmanaged APIs that use a type alias for C or C++'s float on 32-bit platforms + /// or double on 64-bit platforms, such as the CGFloat type in libraries provided by Apple. + /// [Intrinsic] public readonly struct NFloat : IEquatable { private readonly NativeType _value; + /// + /// Constructs an instance from a 32-bit floating point value. + /// + /// The floating-point vaule. public NFloat(float value) { _value = value; } + /// + /// Constructs an instance from a 64-bit floating point value. + /// + /// The floating-point vaule. public NFloat(double value) { #if TARGET_32BIT - if (value > NativeType.MaxValue) + if (value > NativeType.MaxValue || value < NativeType.MinValue) { throw new OverflowException(); } @@ -33,14 +48,35 @@ public NFloat(double value) _value = (NativeType)value; } + /// + /// The underlying floating-point value of this instance. + /// public double Value => _value; + /// + /// Returns a value indicating whether this instance is equal to a specified object. + /// + /// An object to compare with this instance. + /// true if is an instance of and equals the value of this instance; otherwise, false. public override bool Equals(object? o) => o is NFloat other && Equals(other); + /// + /// Returns a value indicating whether this instance is equal to a specified value. + /// + /// An value to compare to this instance. + /// true if has the same value as this instance; otherwise, false. public bool Equals(NFloat other) => _value == other._value; + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. public override int GetHashCode() => _value.GetHashCode(); + /// + /// Converts the numeric value of this instance to its equivalent string representation. + /// + /// The string representation of the value of this instance. public override string ToString() => _value.ToString(); } } From 62acb9ef3049e8d03660772d1e6b2090c88163ac Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 4 Jan 2021 12:32:48 -0800 Subject: [PATCH 11/20] Don't throw on float out of range. Rename tests. --- .../src/System/Runtime/InteropServices/NFloat.cs | 6 ------ .../System/Runtime/InteropServices/CULongTests.cs | 8 ++++---- .../System/Runtime/InteropServices/NFloatTests.cs | 11 ++++++----- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index 1fe0a5a62727f..ad52d42672f0d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -39,12 +39,6 @@ public NFloat(float value) /// The floating-point vaule. public NFloat(double value) { -#if TARGET_32BIT - if (value > NativeType.MaxValue || value < NativeType.MinValue) - { - throw new OverflowException(); - } -#endif _value = (NativeType)value; } diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs index dcf0bffad6ea3..0bb31ed910bc6 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs @@ -25,27 +25,27 @@ public void Ctor_Empty() } [Fact] - public void Ctor_Int() + public void Ctor_UInt() { CULong value = new CULong(42u); Assert.Equal(42u, value.Value); } [Fact] - public void Ctor_NInt() + public void Ctor_NUInt() { CULong value = new CULong((nuint)42); Assert.Equal(42u, value.Value); } [ConditionalFact(nameof(NativeIntConstructorCanOverflow))] - public void Ctor_NInt_OutOfRange() + public void Ctor_NUInt_OutOfRange() { Assert.Throws(() => new CULong(unchecked(((nuint)uint.MaxValue) + 1))); } [ConditionalFact(nameof(NativeIntConstructorCannotOverflow))] - public void Ctor_NInt_LargeValue() + public void Ctor_NUInt_LargeValue() { nuint largeValue = unchecked(((nuint)uint.MaxValue) + 1); CULong value = new CULong(largeValue); diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index c9480c073d027..86d15e8f8ee4e 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -20,27 +20,28 @@ public void Ctor_Empty() } [Fact] - public void Ctor_Int() + public void Ctor_Float() { NFloat value = new NFloat(42.0f); Assert.Equal(42.0, value.Value); } [Fact] - public void Ctor_NInt() + public void Ctor_Double() { NFloat value = new NFloat(42.0); Assert.Equal(42.0, value.Value); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] - public void Ctor_NInt_OutOfRange() + public void Ctor_Double_OutOfRange() { - Assert.Throws(() => new NFloat(double.MaxValue)); + NFloat value = new NFloat(double.MaxValue); + Assert.Equal((double)(float)double.MaxValue, value.Value); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] - public void Ctor_NInt_LargeValue() + public void Ctor_Double_LargeValue() { NFloat value = new NFloat(double.MaxValue); Assert.Equal(double.MaxValue, value.Value); From a365f26bff2365b451a274a67bf14ff5ee67132d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 7 Jan 2021 16:09:47 -0800 Subject: [PATCH 12/20] Rewrite EqualsTest implementations more straightforward. --- .../Runtime/InteropServices/CLongTests.cs | 38 +++++++++---------- .../Runtime/InteropServices/CULongTests.cs | 33 ++++++++-------- .../Runtime/InteropServices/NFloatTests.cs | 33 ++++++++-------- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs index bf9f2afd0ee6c..aed43a76424b2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs @@ -52,29 +52,29 @@ public void Ctor_NInt_LargeValue() Assert.Equal(largeValue, value.Value); } + public static IEnumerable EqualsData() + { + yield return new object[] { new CLong(789), new CLong(789), true }; + yield return new object[] { new CLong(789), new CLong(-789), false }; + yield return new object[] { new CLong(789), new CLong(0), false }; + yield return new object[] { new CLong(0), new CLong(0), true }; + yield return new object[] { new CLong(-789), new CLong(-789), true }; + yield return new object[] { new CLong(-789), new CLong(789), false }; + yield return new object[] { new CLong(789), null, false }; + yield return new object[] { new CLong(789), "789", false }; + yield return new object[] { new CLong(789), 789, false }; + } + [Theory] - [InlineData(789, 789, true)] - [InlineData(789, -789, false)] - [InlineData(789, 0, false)] - [InlineData(0, 0, true)] - [InlineData(-789, -789, true)] - [InlineData(-789, 789, false)] - [InlineData(789, null, false)] - [InlineData(789, "789", false)] - [InlineData(789, (long)789, false)] - public static void EqualsTest(int i1, object obj, bool expected) + [MemberData(nameof(EqualsData))] + public void EqualsTest(CLong clong, object obj, bool expected) { - if (obj is int i) - { - CLong i2 = new CLong(i); - Assert.Equal(expected, new CLong(i1).Equals((object)i2)); - Assert.Equal(expected, new CLong(i1).Equals(i2)); - Assert.Equal(expected, new CLong(i1).GetHashCode().Equals(i2.GetHashCode())); - } - else + if (obj is CLong clong2) { - Assert.Equal(expected, new CLong(i1).Equals(obj)); + Assert.Equal(expected, clong.Equals(clong2)); + Assert.Equal(expected, clong.GetHashCode().Equals(clong2.GetHashCode())); } + Assert.Equal(expected, clong.Equals(obj)); } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs index 0bb31ed910bc6..1f7b220af04ac 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs @@ -52,28 +52,29 @@ public void Ctor_NUInt_LargeValue() Assert.Equal(largeValue, value.Value); } + public static IEnumerable EqualsData() + { + yield return new object[] { new CULong(789), new CULong(789), true }; + yield return new object[] { new CULong(789), new CULong(0), false }; + yield return new object[] { new CULong(0), new CULong(0), true }; + yield return new object[] { new CULong(789), null, false }; + yield return new object[] { new CULong(789), "789", false }; + yield return new object[] { new CULong(789), 789u, false }; + } + [Theory] - [InlineData(789, 789, true)] - [InlineData(789, 0, false)] - [InlineData(0, 0, true)] - [InlineData(789, null, false)] - [InlineData(789, "789", false)] - [InlineData(789, (long)789, false)] - public static void EqualsTest(uint i1, object obj, bool expected) + [MemberData(nameof(EqualsData))] + public void EqualsTest(CULong culong, object obj, bool expected) { - if (obj is uint i) + if (obj is CULong culong2) { - CULong i2 = new CULong(i); - Assert.Equal(expected, new CULong(i1).Equals((object)i2)); - Assert.Equal(expected, new CULong(i1).Equals(i2)); - Assert.Equal(expected, new CULong(i1).GetHashCode().Equals(i2.GetHashCode())); - } - else - { - Assert.Equal(expected, new CULong(i1).Equals(obj)); + Assert.Equal(expected, culong.Equals(culong2)); + Assert.Equal(expected, culong.GetHashCode().Equals(culong2.GetHashCode())); } + Assert.Equal(expected, culong.Equals(obj)); } + [Theory] [InlineData(0, "0")] [InlineData(4567, "4567")] diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index 86d15e8f8ee4e..844e12402307e 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -47,26 +47,27 @@ public void Ctor_Double_LargeValue() Assert.Equal(double.MaxValue, value.Value); } + public static IEnumerable EqualsData() + { + yield return new object[] { new NFloat(789.0f), new NFloat(789.0f), true }; + yield return new object[] { new NFloat(789.0f), new NFloat(-789.0f), false }; + yield return new object[] { new NFloat(789.0f), new NFloat(0.0f), false }; + yield return new object[] { new NFloat(float.NaN), new NFloat(float.NaN), false }; + yield return new object[] { new NFloat(789.0f), 789.0f, false }; + yield return new object[] { new NFloat(789.0f), "789.0", false }; + } + [Theory] - [InlineData(789.0f, 789.0f, true)] - [InlineData(789.0f, -789.0f, false)] - [InlineData(789.0f, 0.0f, false)] - [InlineData(float.NaN, float.NaN, true)] - [InlineData(789.0f, 789.0, false)] - [InlineData(789.0f, "789", false)] - public static void EqualsTest(float f1, object obj, bool expected) + [MemberData(nameof(EqualsData))] + public void EqualsTest(NFloat f1, object obj, bool expected) { - if (obj is float f) - { - NFloat f2 = new NFloat(f); - Assert.Equal(expected, new NFloat(f1).Equals((object)f2)); - Assert.Equal(expected, new NFloat(f1).Equals(f2)); - Assert.Equal(expected, new NFloat(f1).GetHashCode().Equals(f2.GetHashCode())); - } - else + if (obj is NFloat f2) { - Assert.Equal(expected, new NFloat(f1).Equals(obj)); + Assert.Equal(expected, f1.Equals((object)f2)); + Assert.Equal(expected, f1.Equals(f2)); + Assert.Equal(expected, f1.GetHashCode().Equals(f2.GetHashCode())); } + Assert.Equal(expected, f1.Equals(obj)); } [Theory] From b114e7e529f9afc6ca8ebe643b1dd1c2553ad150 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Jan 2021 10:27:40 -0800 Subject: [PATCH 13/20] Fix NFloat tests. --- .../Runtime/InteropServices/NFloatTests.cs | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index 844e12402307e..4e8fc0dfbeda9 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -52,7 +52,6 @@ public static IEnumerable EqualsData() yield return new object[] { new NFloat(789.0f), new NFloat(789.0f), true }; yield return new object[] { new NFloat(789.0f), new NFloat(-789.0f), false }; yield return new object[] { new NFloat(789.0f), new NFloat(0.0f), false }; - yield return new object[] { new NFloat(float.NaN), new NFloat(float.NaN), false }; yield return new object[] { new NFloat(789.0f), 789.0f, false }; yield return new object[] { new NFloat(789.0f), "789.0", false }; } @@ -70,7 +69,15 @@ public void EqualsTest(NFloat f1, object obj, bool expected) Assert.Equal(expected, f1.Equals(obj)); } - [Theory] + [Fact] + public void NaNEqualsTest() + { + NFloat f1 = new NFloat(float.NaN); + NFloat f2 = new NFloat(float.NaN); + Assert.Equal(f1.Value == f2.Value, f1.Equals(f2)); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] [InlineData(-4567.0f, "-4567")] [InlineData(-4567.89101f, "-4567.89111328125")] [InlineData(0.0f, "0")] @@ -78,7 +85,22 @@ public void EqualsTest(NFloat f1, object obj, bool expected) [InlineData(4567.89101f, "4567.89111328125")] [InlineData(float.NaN, "NaN")] - public static void ToStringTest(float value, string expected) + public static void ToStringTest64(float value, string expected) + { + NFloat nfloat = new NFloat(value); + + Assert.Equal(expected, nfloat.ToString()); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData(-4567.0f, "-4567")] + [InlineData(-4567.89101f, "-4567.891")] + [InlineData(0.0f, "0")] + [InlineData(4567.0f, "4567")] + [InlineData(4567.89101f, "4567.891")] + + [InlineData(float.NaN, "NaN")] + public static void ToStringTest32(float value, string expected) { NFloat nfloat = new NFloat(value); From 265a9141d4e0d2fb4c243ec67d78803ddeb98af4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Jan 2021 10:39:39 -0800 Subject: [PATCH 14/20] Use .Equals instead of == --- .../src/System/Runtime/InteropServices/NFloat.cs | 2 +- .../tests/System/Runtime/InteropServices/NFloatTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index ad52d42672f0d..468d3e55ed5df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -59,7 +59,7 @@ public NFloat(double value) /// /// An value to compare to this instance. /// true if has the same value as this instance; otherwise, false. - public bool Equals(NFloat other) => _value == other._value; + public bool Equals(NFloat other) => _value.Equals(other._value); /// /// Returns the hash code for this instance. diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index 4e8fc0dfbeda9..066b00a1ab388 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -74,7 +74,7 @@ public void NaNEqualsTest() { NFloat f1 = new NFloat(float.NaN); NFloat f2 = new NFloat(float.NaN); - Assert.Equal(f1.Value == f2.Value, f1.Equals(f2)); + Assert.Equal(f1.Value.Equals(f2.Value), f1.Equals(f2)); } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] From 5404cecbd0dca1e46e979766ef48e3a07d45910f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Jan 2021 13:57:40 -0800 Subject: [PATCH 15/20] Use ToString directly instead of hard coding the expected value. --- .../Runtime/InteropServices/NFloatTests.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index 066b00a1ab388..11d70ca8652f1 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -78,33 +78,33 @@ public void NaNEqualsTest() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] - [InlineData(-4567.0f, "-4567")] - [InlineData(-4567.89101f, "-4567.89111328125")] - [InlineData(0.0f, "0")] - [InlineData(4567.0f, "4567")] - [InlineData(4567.89101f, "4567.89111328125")] + [InlineData(-4567.0f)] + [InlineData(-4567.89101f)] + [InlineData(0.0f)] + [InlineData(4567.0f)] + [InlineData(4567.89101f)] - [InlineData(float.NaN, "NaN")] - public static void ToStringTest64(float value, string expected) + [InlineData(float.NaN)] + public static void ToStringTest64(float value) { NFloat nfloat = new NFloat(value); - Assert.Equal(expected, nfloat.ToString()); + Assert.Equal(((double)value).ToString(), nfloat.ToString()); } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] - [InlineData(-4567.0f, "-4567")] - [InlineData(-4567.89101f, "-4567.891")] - [InlineData(0.0f, "0")] - [InlineData(4567.0f, "4567")] - [InlineData(4567.89101f, "4567.891")] + [InlineData(-4567.0f)] + [InlineData(-4567.89101f)] + [InlineData(0.0f)] + [InlineData(4567.0f)] + [InlineData(4567.89101f)] - [InlineData(float.NaN, "NaN")] - public static void ToStringTest32(float value, string expected) + [InlineData(float.NaN)] + public static void ToStringTest32(float value) { NFloat nfloat = new NFloat(value); - Assert.Equal(expected, nfloat.ToString()); + Assert.Equal(value.ToString(), nfloat.ToString()); } } } From cac95b4bd58f6b494236dac7191e2f71c4450857 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Jan 2021 15:10:35 -0800 Subject: [PATCH 16/20] Update the emitted assembly stub's thiscall retbuf support for x86 to account for the new native exchange types. --- src/coreclr/vm/dllimportcallback.cpp | 37 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index 1a50a5e7c9898..e1095cb5bc622 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -178,7 +178,7 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo, // push edx - repush the return address pcpusl->X86EmitPushReg(kEDX); } - + // The native signature doesn't have a return buffer // but the managed signature does. // Set up the return buffer address here. @@ -188,12 +188,12 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo, // Calculate the offset to the return buffer we establish for EAX:EDX below. // lea edx [esp - offset to EAX:EDX return buffer] pcpusl->X86EmitEspOffset(0x8d, kEDX, -0xc /* skip return addr, EBP, EBX */ -0x8 /* point to start of EAX:EDX return buffer */ ); - + // exchange edx (which has the return buffer address) // with the return address // xchg edx, [esp] - pcpusl->X86EmitOp(0x87, kEDX, (X86Reg)kESP_Unsafe); - + pcpusl->X86EmitOp(0x87, kEDX, (X86Reg)kESP_Unsafe); + // push edx pcpusl->X86EmitPushReg(kEDX); } @@ -497,7 +497,7 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo, pcpusl->X86EmitIndexRegStore(kEBX, -0x8 /* to outer EBP */ -0x8 /* skip saved EBP, EBX */, kEDX); } // In the umtmlBufRetValToEnreg case, - // we set up the return buffer to output + // we set up the return buffer to output // into the EDX:EAX buffer we set up for the register return case. // So we don't need to do more work here. else if ((pInfo->m_wFlags & umtmlBufRetValToEnreg) == 0) @@ -684,7 +684,7 @@ Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStat UINT nOffset = 0; int numRegistersUsed = 0; int numStackSlotsIndex = nStackBytes / STACK_ELEM_SIZE; - + // This could have been set in the UnmanagedCallersOnly scenario. if (m_callConv == UINT16_MAX) m_callConv = static_cast(pSigInfo->GetCallConv()); @@ -699,8 +699,29 @@ Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStat numRegistersUsed++; } + bool hasReturnBuffer = argit.HasRetBuffArg() || (m_callConv == pmCallConvThiscall && argit.HasValueTypeReturn()); + bool hasNativeExchangeTypeReturn = false; + + if (hasReturnBuffer) + { + // If think we have a return buffer, lets make sure that we aren't returning one of the intrinsic native exchange types. + TypeHandle returnType = pMetaSig->GetRetTypeHandleThrowing(); + if (returnType.GetMethodTable()->IsIntrinsicType()) + { + LPCUTF8 pszNamespace; + returnType.GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace); + if (strcmp(pszNamespace, g_InteropServicesNS) == 0) + { + // We have one of the intrinsic native exchange types. + // As a result, we don't have a return buffer. + hasReturnBuffer = false; + hasNativeExchangeTypeReturn = true; + } + } + } + // process the return buffer parameter - if (argit.HasRetBuffArg() || (m_callConv == pmCallConvThiscall && argit.HasValueTypeReturn())) + if (hasReturnBuffer) { // Only copy the retbuf arg from the src call when both the managed call and native call // have a return buffer. @@ -808,7 +829,7 @@ Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStat { stubInfo.m_wFlags |= umtmlThisCallHiddenArg; } - else if (argit.HasValueTypeReturn()) + else if (argit.HasValueTypeReturn() && !hasNativeExchangeTypeReturn) { stubInfo.m_wFlags |= umtmlThisCallHiddenArg | umtmlEnregRetValToBuf; // When the native signature has a return buffer but the From 59785f52264c28d29d1cfcec5331ef193e1502c7 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Jan 2021 15:23:06 -0800 Subject: [PATCH 17/20] Add sizeof tests. --- .../System/Runtime/InteropServices/CLongTests.cs | 12 +++++++++++- .../System/Runtime/InteropServices/CULongTests.cs | 12 +++++++++++- .../System/Runtime/InteropServices/NFloatTests.cs | 10 ++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs index aed43a76424b2..95c05c0f0f37a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CLongTests.cs @@ -12,7 +12,7 @@ namespace System.Runtime.InteropServices.Tests { public class CLongTests { - private static bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; + private static bool Has64BitStorage => !Has32BitStorage; private static bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; private static bool NativeIntConstructorCanOverflow => !PlatformDetection.Is32BitProcess && Has32BitStorage; private static bool NativeIntConstructorCannotOverflow => !NativeIntConstructorCanOverflow; @@ -89,5 +89,15 @@ public static void ToStringTest(int value, string expected) Assert.Equal(expected, clong.ToString()); } + + [Fact] + public unsafe void Size() + { + int size = Has32BitStorage ? 4 : 8; +#pragma warning disable xUnit2000 // The value under test here is the sizeof expression + Assert.Equal(size, sizeof(CLong)); +#pragma warning restore xUnit2000 + Assert.Equal(size, Marshal.SizeOf()); + } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs index 1f7b220af04ac..dc1cb30f68cec 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/CULongTests.cs @@ -12,7 +12,7 @@ namespace System.Runtime.InteropServices.Tests { public class CULongTests { - private static bool Has64BitStorage => !PlatformDetection.Is32BitProcess && !PlatformDetection.IsWindows; + private static bool Has64BitStorage => !Has32BitStorage; private static bool Has32BitStorage => PlatformDetection.Is32BitProcess || PlatformDetection.IsWindows; private static bool NativeIntConstructorCanOverflow => !PlatformDetection.Is32BitProcess && Has32BitStorage; private static bool NativeIntConstructorCannotOverflow => !NativeIntConstructorCanOverflow; @@ -85,5 +85,15 @@ public static void ToStringTest(uint value, string expected) Assert.Equal(expected, culong.ToString()); } + + [Fact] + public unsafe void Size() + { + int size = Has32BitStorage ? 4 : 8; +#pragma warning disable xUnit2000 // The value under test here is the sizeof expression + Assert.Equal(size, sizeof(CULong)); +#pragma warning restore xUnit2000 + Assert.Equal(size, Marshal.SizeOf()); + } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs index 11d70ca8652f1..c2311afae708d 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/NFloatTests.cs @@ -106,5 +106,15 @@ public static void ToStringTest32(float value) Assert.Equal(value.ToString(), nfloat.ToString()); } + + [Fact] + public unsafe void Size() + { + int size = PlatformDetection.Is32BitProcess ? 4 : 8; +#pragma warning disable xUnit2000 // The value under test here is the sizeof expression + Assert.Equal(size, sizeof(NFloat)); +#pragma warning restore xUnit2000 + Assert.Equal(size, Marshal.SizeOf()); + } } } From 65eddf767fc74889a50e2a6945ea8587025b0ee4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Jan 2021 15:35:08 -0800 Subject: [PATCH 18/20] Add test with struct containing CLong. --- .../PInvoke/MarshalStructAsLayoutSeq.cs | 255 ++++++++++-------- .../PInvoke/MarshalStructAsParamDLL.cpp | 9 +- .../PInvoke/MarshalStructAsParamDLL.h | 40 +-- .../StructMarshalling/PInvoke/Struct.cs | 12 +- 4 files changed, 183 insertions(+), 133 deletions(-) diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs index b096b13a9770d..837027c323630 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs @@ -31,7 +31,8 @@ enum StructID FixedBufferClassificationTestId, UnicodeCharArrayClassificationId, HFAId, - DoubleHFAId + DoubleHFAId, + Int32CLongId } private static void InitialArray(int[] iarr, int[] icarr) @@ -335,13 +336,16 @@ public static int Main() [DllImport("MarshalStructAsParam")] static extern HFA GetHFA(float f1, float f2, float f3, float f4); - + [DllImport("MarshalStructAsParam")] static extern float ProductHFA(HFA hfa); [DllImport("MarshalStructAsParam")] static extern double ProductDoubleHFA(DoubleHFA hfa); + [DllImport("MarshalStructAsParam")] + static extern Int32CLongStruct AddCLongs(Int32CLongStruct lhs, Int32CLongStruct rhs); + [DllImport("MarshalStructAsParam")] static extern ManyInts GetMultiplesOf(int i); @@ -376,7 +380,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential clone_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); @@ -391,7 +395,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential clone_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); @@ -406,7 +410,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential clone_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); @@ -421,7 +425,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential clone_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); @@ -436,7 +440,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -455,7 +459,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumcl = Enum1.e1; @@ -473,7 +477,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -490,7 +494,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -507,7 +511,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 cloneS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); @@ -522,7 +526,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 cloneS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); @@ -537,7 +541,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential cloneIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); @@ -552,7 +556,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 cloneS11 = Helper.NewS11((int*)new Int64(), 32); @@ -594,7 +598,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValIntWithInnerSequential.Expected:True;Actual:False"); failures++; } - break; + break; case StructID.SequentialWrapperId: SequentialWrapper sequentialWrapper = new SequentialWrapper { @@ -606,7 +610,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValSequentialWrapper.Expected:True;Actual:False"); failures++; } - break; + break; case StructID.SequentialDoubleWrapperId: SequentialDoubleWrapper doubleWrapper = new SequentialDoubleWrapper { @@ -621,7 +625,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValSequentialDoubleWrapper.Expected:True;Actual:False"); failures++; } - break; + break; case StructID.AggregateSequentialWrapperId: AggregateSequentialWrapper aggregateWrapper = new AggregateSequentialWrapper { @@ -641,7 +645,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValSequentialAggregateSequentialWrapper.Expected:True;Actual:False"); failures++; } - break; + break; case StructID.FixedBufferClassificationTestId: Console.WriteLine("\tCalling MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest with nonblittable struct..."); unsafe @@ -745,10 +749,38 @@ unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id) } break; } + case StructID.Int32CLongId: + { + Int32CLongStruct str1 = new Int32CLongStruct + { + i = 2, + l = new CLong(30) + }; + Int32CLongStruct str2 = new Int32CLongStruct + { + i = 10, + l = new CLong(50) + }; + + Int32CLongStruct expected = new Int32CLongStruct + { + i = 12, + l = new CLong(80) + }; + + Console.WriteLine("\tCalling AddCLongs."); + Int32CLongStruct actual = AddCLongs(str1, str2); + if (!expected.Equals(actual)) + { + Console.WriteLine($"\tFAILED! Expected {expected}. Actual {actual}"); + failures++; + } + break; + } default: Console.WriteLine("\tThere is not the struct id"); failures++; - break; + break; } } catch (Exception e) @@ -780,7 +812,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential change_ias = Helper.NewInnerArraySequential(77, 77.0F, "changed string"); @@ -809,7 +841,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential change_csus = Helper.NewCharSetUnicodeSequential("change string", 'n'); @@ -824,7 +856,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential change_ns = Helper.NewNumberSequential(0, 32, 0, 16, 0, 8, 0, 16, 0, 64, 64.0F, 6.4); @@ -839,7 +871,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -858,7 +890,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumch = Enum1.e2; @@ -875,7 +907,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -892,7 +924,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -909,7 +941,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 changeS8 = Helper.NewS8("world", "HelloWorldAgain", false, 1, 256, 256, 64); @@ -924,7 +956,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 changeS9 = Helper.NewS9(256, null); @@ -939,7 +971,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential changeIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(64, 64); @@ -954,7 +986,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 changeS11 = Helper.NewS11((int*)(32), 64); @@ -969,11 +1001,11 @@ unsafe private static void MarshalStructAsParam_AsSeqByRef(StructID id) { failures++; } - break; + break; default: Console.WriteLine("\tThere is not the struct id"); failures++; - break; + break; } } catch (Exception e) @@ -1004,7 +1036,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential clone_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); @@ -1019,7 +1051,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential clone_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); @@ -1034,7 +1066,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential clone_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); @@ -1049,7 +1081,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential clone_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); @@ -1064,7 +1096,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -1083,7 +1115,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumcl = Enum1.e1; @@ -1100,7 +1132,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -1117,7 +1149,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -1134,7 +1166,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 cloneS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); @@ -1149,7 +1181,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 cloneS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); @@ -1164,7 +1196,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential cloneIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); @@ -1179,7 +1211,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 cloneS11 = Helper.NewS11((int*)new Int64(), 32); @@ -1199,7 +1231,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValIn(StructID id) default: Console.WriteLine("\tThere is not the struct id"); failures++; - break; + break; } } catch (Exception e) @@ -1230,7 +1262,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential clone_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); @@ -1245,7 +1277,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential clone_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); @@ -1260,7 +1292,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential clone_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); @@ -1275,7 +1307,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential change_ns = Helper.NewNumberSequential(0, 32, 0, 16, 0, 8, 0, 16, 0, 64, 64.0F, 6.4); @@ -1290,7 +1322,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -1309,7 +1341,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumcl = Enum1.e1; @@ -1326,7 +1358,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -1343,7 +1375,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -1360,7 +1392,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 cloneS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); @@ -1375,7 +1407,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 cloneS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); @@ -1390,7 +1422,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential changeIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(64, 64); @@ -1405,7 +1437,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 changeS11 = Helper.NewS11((int*)(32), 64); @@ -1420,11 +1452,11 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefIn(StructID id) { failures++; } - break; + break; default: Console.WriteLine("\tThere is not the struct id"); failures++; - break; + break; } } catch (Exception e) @@ -1455,7 +1487,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential clone_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); @@ -1470,7 +1502,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential clone_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); @@ -1485,7 +1517,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential clone_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); @@ -1500,7 +1532,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential clone_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); @@ -1515,7 +1547,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -1534,7 +1566,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumcl = Enum1.e1; @@ -1551,7 +1583,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -1568,7 +1600,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -1585,7 +1617,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 cloneS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); @@ -1600,7 +1632,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 cloneS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); @@ -1615,7 +1647,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential cloneIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); @@ -1630,7 +1662,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)32, 32); S11 cloneS11 = Helper.NewS11((int*)32, 32); @@ -1645,7 +1677,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValOut(StructID id) { failures++; } - break; + break; default: Console.WriteLine("\tThere is not the struct id"); failures++; @@ -1681,7 +1713,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential change_ias = Helper.NewInnerArraySequential(77, 77.0F, "changed string"); @@ -1696,7 +1728,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential changeStr1 = Helper.NewCharSetAnsiSequential("change string", 'n'); @@ -1711,7 +1743,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential change_csus = Helper.NewCharSetUnicodeSequential("change string", 'n'); @@ -1726,7 +1758,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential change_ns = Helper.NewNumberSequential(0, 32, 0, 16, 0, 8, 0, 16, 0, 64, 64.0F, 6.4); @@ -1741,7 +1773,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -1760,7 +1792,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumch = Enum1.e2; @@ -1777,7 +1809,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -1794,7 +1826,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -1811,7 +1843,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 changeS8 = Helper.NewS8("world", "HelloWorldAgain", false, 1, 256, 256, 64); @@ -1826,7 +1858,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); @@ -1845,7 +1877,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { Console.WriteLine("\tPASSED!"); } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential changeIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(64, 64); @@ -1860,7 +1892,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 changeS11 = Helper.NewS11((int*)(32), 64); @@ -1875,7 +1907,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefOut(StructID id) { failures++; } - break; + break; default: Console.WriteLine("\tThere is not the struct id"); failures++; @@ -1910,7 +1942,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential clone_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); @@ -1925,7 +1957,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential clone_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); @@ -1940,7 +1972,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential clone_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); @@ -1955,7 +1987,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential clone_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); @@ -1970,7 +2002,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -1989,7 +2021,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumcl = Enum1.e1; @@ -2006,7 +2038,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -2023,7 +2055,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -2040,7 +2072,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 cloneS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); @@ -2055,7 +2087,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 cloneS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); @@ -2070,7 +2102,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential cloneIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); @@ -2085,7 +2117,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 cloneS11 = Helper.NewS11((int*)new Int64(), 32); @@ -2100,7 +2132,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByValInOut(StructID id) { failures++; } - break; + break; default: Console.WriteLine("\tThere is not the struct id"); failures++; @@ -2136,7 +2168,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.InnerArraySequentialId: InnerArraySequential source_ias = Helper.NewInnerArraySequential(1, 1.0F, "some string"); InnerArraySequential change_ias = Helper.NewInnerArraySequential(77, 77.0F, "changed string"); @@ -2151,7 +2183,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.CharSetAnsiSequentialId: CharSetAnsiSequential source_csas = Helper.NewCharSetAnsiSequential("some string", 'c'); CharSetAnsiSequential changeStr1 = Helper.NewCharSetAnsiSequential("change string", 'n'); @@ -2166,7 +2198,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.CharSetUnicodeSequentialId: CharSetUnicodeSequential source_csus = Helper.NewCharSetUnicodeSequential("some string", 'c'); CharSetUnicodeSequential change_csus = Helper.NewCharSetUnicodeSequential("change string", 'n'); @@ -2181,7 +2213,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.NumberSequentialId: NumberSequential source_ns = Helper.NewNumberSequential(Int32.MinValue, UInt32.MaxValue, short.MinValue, ushort.MaxValue, byte.MinValue, sbyte.MaxValue, Int16.MinValue, UInt16.MaxValue, -1234567890, 1234567890, 32.0F, 3.2); NumberSequential change_ns = Helper.NewNumberSequential(0, 32, 0, 16, 0, 8, 0, 16, 0, 64, 64.0F, 6.4); @@ -2196,7 +2228,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.S3Id: int[] iarr = new int[256]; int[] icarr = new int[256]; @@ -2215,7 +2247,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.S5Id: Enum1 enums = Enum1.e1; Enum1 enumch = Enum1.e2; @@ -2232,7 +2264,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialAnsiId: strOne = new String('a', 512); strTwo = new String('b', 512); @@ -2249,7 +2281,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.StringStructSequentialUnicodeId: strOne = new String('a', 256); strTwo = new String('b', 256); @@ -2266,7 +2298,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.S8Id: S8 sourceS8 = Helper.NewS8("hello", null, true, 10, 128, 128, 32); S8 changeS8 = Helper.NewS8("world", "HelloWorldAgain", false, 1, 256, 256, 64); @@ -2281,7 +2313,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.S9Id: S9 sourceS9 = Helper.NewS9(128, new TestDelegate1(testMethod)); S9 changeS9 = Helper.NewS9(256, null); @@ -2296,7 +2328,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.IncludeOuterIntegerStructSequentialId: IncludeOuterIntegerStructSequential sourceIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(32, 32); IncludeOuterIntegerStructSequential changeIncludeOuterIntegerStructSequential = Helper.NewIncludeOuterIntegerStructSequential(64, 64); @@ -2311,7 +2343,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; case StructID.S11Id: S11 sourceS11 = Helper.NewS11((int*)new Int32(), 32); S11 changeS11 = Helper.NewS11((int*)(32), 64); @@ -2326,7 +2358,7 @@ unsafe private static void MarshalStructAsParam_AsSeqByRefInOut(StructID id) { failures++; } - break; + break; default: Console.WriteLine("\tThere is not the struct id"); failures++; @@ -2371,6 +2403,7 @@ private static void RunMarshalSeqStructAsParamByVal() MarshalStructAsParam_AsSeqByVal(StructID.UnicodeCharArrayClassificationId); MarshalStructAsParam_AsSeqByVal(StructID.HFAId); MarshalStructAsParam_AsSeqByVal(StructID.DoubleHFAId); + MarshalStructAsParam_AsSeqByVal(StructID.Int32CLongId); } [SecuritySafeCritical] diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp index a7f5d17de6c48..9278650d20dce 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp @@ -1226,7 +1226,7 @@ extern "C" DLL_EXPORT double STDMETHODCALLTYPE ProductDoubleHFA(DoubleHFA hfa) extern "C" DLL_EXPORT ManyInts STDMETHODCALLTYPE GetMultiplesOf(int value) { - ManyInts multiples = + ManyInts multiples = { value * 1, value * 2, @@ -1235,7 +1235,7 @@ extern "C" DLL_EXPORT ManyInts STDMETHODCALLTYPE GetMultiplesOf(int value) value * 5, value * 6, value * 7, - value * 8, + value * 8, value * 9, value * 10, value * 11, @@ -1292,3 +1292,8 @@ extern "C" DLL_EXPORT void STDMETHODCALLTYPE MarshalStructAsParam_DelegateFieldM { // Nothing to do } + +extern "C" DLL_EXPORT Int32CLongStruct STDMETHODCALLTYPE AddCLongs(Int32CLongStruct lhs, Int32CLongStruct rhs) +{ + return { lhs.i + rhs.i, lhs.l + rhs.l }; +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h index a300af22d18f1..4a74572717890 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h @@ -87,7 +87,7 @@ bool IsCorrectINNER2(INNER2* p) } -struct InnerExplicit +struct InnerExplicit { #ifdef WINDOWS union @@ -97,7 +97,7 @@ struct InnerExplicit }; CHAR _unused0[4]; LPCSTR f3; - #endif + #endif #ifndef WINDOWS union @@ -107,7 +107,7 @@ struct InnerExplicit }; INT _unused0; LPCSTR f3; - #endif + #endif }; @@ -169,13 +169,13 @@ union InnerArrayExplicit { LONG64 _unused0; LPCSTR f4; - } s; + } s; }; #ifdef WINDOWS #ifdef HOST_64BIT -#pragma warning(push) +#pragma warning(push) #pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union union OUTER3 { @@ -285,7 +285,7 @@ bool IsCorrectCharSetAnsiSequential(CharSetAnsiSequential* p) } -struct CharSetUnicodeSequential +struct CharSetUnicodeSequential { LPCWSTR f1; WCHAR f2; @@ -346,15 +346,15 @@ struct NumberSequential LONG64 i64; ULONG64 ui64; DOUBLE d; - INT i32; - UINT ui32; - SHORT s1; - WORD us1; - SHORT i16; + INT i32; + UINT ui32; + SHORT s1; + WORD us1; + SHORT i16; WORD ui16; FLOAT sgl; - BYTE b; - CHAR sb; + BYTE b; + CHAR sb; }; void PrintNumberSequential(NumberSequential* str, char const * name) { @@ -454,10 +454,10 @@ struct S4 INT age; LPCSTR name; }; -enum Enum1 +enum Enum1 { e1 = 1, - e2 = 3 + e2 = 3 }; struct S5 { @@ -529,7 +529,7 @@ void ChangeStringStructSequentialAnsi(StringStructSequentialAnsi* str) newFirst[512] = '\0'; newLast[512] = '\0'; - str->first = newFirst; + str->first = newFirst; str->last = newLast; } @@ -938,7 +938,7 @@ union OverlappingMultipleEightbyte float arr[3]; struct { - float padding[2]; + float padding[2]; int i; }; }; @@ -968,3 +968,9 @@ struct UnicodeCharArrayClassification WCHAR arr[6]; float f; }; + +struct Int32CLongStruct +{ + int32_t i; + long l; +}; diff --git a/src/tests/Interop/StructMarshalling/PInvoke/Struct.cs b/src/tests/Interop/StructMarshalling/PInvoke/Struct.cs index 293204527469f..ec47ca4945629 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/Struct.cs +++ b/src/tests/Interop/StructMarshalling/PInvoke/Struct.cs @@ -73,7 +73,7 @@ public struct INNER2 public int f1; [FieldOffset(4)] public float f2; - [FieldOffset(8)] + [FieldOffset(8)] public String f3; } @@ -145,7 +145,7 @@ public struct NumberSequential public UInt16 ui16; public Single sgl; public Byte b; - public SByte sb; + public SByte sb; } [StructLayout(LayoutKind.Sequential)] @@ -471,7 +471,7 @@ public NonBlittableFloat(float f) [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] private float[] arr; - + public float F => arr[0]; } @@ -503,3 +503,9 @@ public struct DelegateFieldMarshaling { public Delegate IntIntFunction; } + +public struct Int32CLongStruct +{ + public int i; + public CLong l; +} From 314e03ae2c31ccc04c54b423fa9c230662df6233 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jan 2021 11:26:26 -0800 Subject: [PATCH 19/20] Disable ThisCallTest on Mono due to #46820 --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 41db21445c172..b8ebbfcaed1f8 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1233,6 +1233,9 @@ needs triage + + https://github.com/dotnet/runtime/issues/46820 + needs triage From 19e0063230d41f2d14314d486537ed0fcef12dca Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 12 Jan 2021 11:51:33 -0800 Subject: [PATCH 20/20] validate type name. --- src/coreclr/vm/dllimportcallback.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index e1095cb5bc622..337876d7b9257 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -709,8 +709,9 @@ Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStat if (returnType.GetMethodTable()->IsIntrinsicType()) { LPCUTF8 pszNamespace; - returnType.GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace); - if (strcmp(pszNamespace, g_InteropServicesNS) == 0) + LPCUTF8 pszTypeName = returnType.GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace); + if ((strcmp(pszNamespace, g_InteropServicesNS) == 0) + && (strcmp(pszTypeName, "CLong") == 0 || strcmp(pszTypeName, "CULong") == 0 || strcmp(pszTypeName, "NFloat") == 0)) { // We have one of the intrinsic native exchange types. // As a result, we don't have a return buffer.