-
Notifications
You must be signed in to change notification settings - Fork 5k
Implement System.Runtime.InteropServices.CLong/CULong/NFloat #46401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e8872a4
3b7693b
e598892
c9d8d13
0aeaaf7
2baa10d
57ba638
d2da1d8
f141023
e587cfc
5b9d7a3
62acb9e
a365f26
b114e7e
265a914
5404cec
cac95b4
59785f5
65eddf7
3e2ded1
314e03a
b285a8a
19e0063
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -560,6 +560,35 @@ 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) | ||
jkoritzinsky marked this conversation as resolved.
Show resolved
Hide resolved
jkoritzinsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
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 +1042,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)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, it looks like this call is expensive, should we measure TP on x64 windows? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this be expensive since its initially filtered on |
||
{ | ||
canReturnInRegister = false; | ||
howToReturnStruct = SPK_ByReference; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5046,6 +5046,10 @@ 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 | ||
|
@@ -8045,6 +8049,21 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
#endif | ||
} | ||
|
||
bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was it just moved or do I miss an actual change for these 3 functions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was just moved out of the FEATURE_SIMD block. |
||
{ | ||
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? | ||
|
@@ -8263,21 +8282,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()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// 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; | ||
#else | ||
using NativeType = System.IntPtr; | ||
#endif | ||
|
||
namespace System.Runtime.InteropServices | ||
{ | ||
/// <summary> | ||
/// <see cref="CLong"/> is an immutable value type that represents the <c>long</c> 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 <c>long</c> 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. | ||
/// </summary> | ||
[CLSCompliant(false)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means this type isn't compliant in VB.NET. Which means APIs that decide to use it will not be consumable by VB.NET. Unsure if that is okay or not. I am fine with it but let's make sure we do our due diligence and confirm that shared understanding. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'm no expert in VB though, so it's definitely plausible that I'm unaware of some detail 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there anything actually preventing the use of this from other languages given it is just a struct wrapping a |
||
[Intrinsic] | ||
public readonly struct CLong : IEquatable<CLong> | ||
{ | ||
private readonly NativeType _value; | ||
|
||
/// <summary> | ||
/// Constructs an instance from a 32-bit integer. | ||
/// </summary> | ||
/// <param name="value">The integer vaule.</param> | ||
public CLong(int value) | ||
{ | ||
_value = (NativeType)value; | ||
} | ||
jkoritzinsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// <summary> | ||
/// Constructs an instance from a native sized integer. | ||
/// </summary> | ||
/// <param name="value">The integer vaule.</param> | ||
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of the underlying storage type.</exception> | ||
public CLong(nint value) | ||
{ | ||
_value = checked((NativeType)value); | ||
} | ||
|
||
/// <summary> | ||
/// The underlying integer value of this instance. | ||
/// </summary> | ||
public nint Value => _value; | ||
|
||
/// <summary> | ||
/// Returns a value indicating whether this instance is equal to a specified object. | ||
/// </summary> | ||
/// <param name="o">An object to compare with this instance.</param> | ||
/// <returns><c>true</c> if <paramref name="o"/> is an instance of <see cref="CLong"/> and equals the value of this instance; otherwise, <c>false</c>.</returns> | ||
public override bool Equals(object? o) => o is CLong other && Equals(other); | ||
|
||
/// <summary> | ||
/// Returns a value indicating whether this instance is equal to a specified <see cref="CLong"/> value. | ||
/// </summary> | ||
/// <param name="other">A <see cref="CLong"/> value to compare to this instance.</param> | ||
/// <returns><c>true</c> if <paramref name="other"/> has the same value as this instance; otherwise, <c>false</c>.</returns> | ||
public bool Equals(CLong other) => _value == other._value; | ||
|
||
/// <summary> | ||
/// Returns the hash code for this instance. | ||
/// </summary> | ||
/// <returns>A 32-bit signed integer hash code.</returns> | ||
public override int GetHashCode() => _value.GetHashCode(); | ||
|
||
/// <summary> | ||
/// Converts the numeric value of this instance to its equivalent string representation. | ||
/// </summary> | ||
/// <returns>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.</returns> | ||
public override string ToString() => _value.ToString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// 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; | ||
#else | ||
using NativeType = System.UIntPtr; | ||
#endif | ||
|
||
namespace System.Runtime.InteropServices | ||
{ | ||
/// <summary> | ||
/// <see cref="CULong"/> is an immutable value type that represents the <c>unsigned long</c> 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 <c>unsigned long</c> 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. | ||
/// </summary> | ||
[CLSCompliant(false)] | ||
[Intrinsic] | ||
public readonly struct CULong : IEquatable<CULong> | ||
{ | ||
private readonly NativeType _value; | ||
|
||
/// <summary> | ||
/// Constructs an instance from a 32-bit unsigned integer. | ||
/// </summary> | ||
/// <param name="value">The integer vaule.</param> | ||
public CULong(uint value) | ||
{ | ||
_value = (NativeType)value; | ||
} | ||
jkoritzinsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// <summary> | ||
/// Constructs an instance from a native sized unsigned integer. | ||
/// </summary> | ||
/// <param name="value">The integer vaule.</param> | ||
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of the underlying storage type.</exception> | ||
public CULong(nuint value) | ||
{ | ||
_value = checked((NativeType)value); | ||
} | ||
|
||
/// <summary> | ||
/// The underlying integer value of this instance. | ||
/// </summary> | ||
public nuint Value => _value; | ||
|
||
/// <summary> | ||
/// Returns a value indicating whether this instance is equal to a specified object. | ||
/// </summary> | ||
/// <param name="o">An object to compare with this instance.</param> | ||
/// <returns><c>true</c> if <paramref name="o"/> is an instance of <see cref="CULong"/> and equals the value of this instance; otherwise, <c>false</c>.</returns> | ||
public override bool Equals(object? o) => o is CULong other && Equals(other); | ||
|
||
/// <summary> | ||
/// Returns a value indicating whether this instance is equal to a specified <see cref="CLong"/> value. | ||
/// </summary> | ||
/// <param name="other">A <see cref="CULong"/> value to compare to this instance.</param> | ||
/// <returns><c>true</c> if <paramref name="other"/> has the same value as this instance; otherwise, <c>false</c>.</returns> | ||
public bool Equals(CULong other) => _value == other._value; | ||
|
||
/// <summary> | ||
/// Returns the hash code for this instance. | ||
/// </summary> | ||
/// <returns>A 32-bit signed integer hash code.</returns> | ||
public override int GetHashCode() => _value.GetHashCode(); | ||
|
||
/// <summary> | ||
/// Converts the numeric value of this instance to its equivalent string representation. | ||
/// </summary> | ||
/// <returns>The string representation of the value of this instance, consisting of a sequence of digits ranging from 0 to 9 with no leading zeroes.</returns> | ||
public override string ToString() => _value.ToString(); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.