From a3859fab9cd686824cd9df77a6510033a6a44174 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 24 May 2021 11:00:29 -0700 Subject: [PATCH 1/2] Integrate selected changes from nativeaot branch - More code sharing for System.Exception - Some support for default interface methods - Move callling convention helpers around to avoid duplication --- .../src/System/Exception.CoreCLR.cs | 46 +----------- .../tools/Common/Compiler/TypeExtensions.cs | 59 +++++++++++++++ .../Common/JitInterface/CallConvHelper.cs | 42 ----------- .../tools/Common/JitInterface/CorInfoImpl.cs | 13 ++-- .../Common/MetadataVirtualMethodAlgorithm.cs | 74 +++++++++++++++++++ .../TypeSystem/Common/TypeSystemHelpers.cs | 5 ++ .../Common/VirtualMethodAlgorithm.cs | 25 +++++++ .../TypeSystem/Interop/CallConvHelpers.cs} | 59 ++++++++------- .../ILCompiler.ReadyToRun.csproj | 9 +-- .../TestUtilities/System/PlatformDetection.cs | 2 +- .../System/Diagnostics/Tracing/EventSource.cs | 2 + .../src/System/Exception.cs | 44 +++++++++++ .../System/Runtime/InteropServices/Marshal.cs | 32 +++++++- .../src/System/Exception.Mono.cs | 43 +---------- 14 files changed, 289 insertions(+), 166 deletions(-) delete mode 100644 src/coreclr/tools/Common/JitInterface/CallConvHelper.cs rename src/coreclr/tools/{aot/ILCompiler.ReadyToRun/Compiler/MethodExtensions.cs => Common/TypeSystem/Interop/CallConvHelpers.cs} (57%) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs index 2be63740dc34c..8a0c9402cb54c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs @@ -85,35 +85,6 @@ public MethodBase? TargetSite } } - // Returns the stack trace as a string. If no stack trace is - // available, null is returned. - public virtual string? StackTrace - { - get - { - string? stackTraceString = _stackTraceString; - string? remoteStackTraceString = _remoteStackTraceString; - - // if no stack trace, try to get one - if (stackTraceString != null) - { - return remoteStackTraceString + stackTraceString; - } - if (_stackTrace == null) - { - return remoteStackTraceString; - } - - return remoteStackTraceString + GetStackTrace(); - } - } - - private string GetStackTrace() - { - // Do not include a trailing newline for backwards compatibility - return new StackTrace(this, fNeedFileInfo: true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); - } - private string? CreateSourceName() { StackTrace st = new StackTrace(this, fNeedFileInfo: false); @@ -243,22 +214,9 @@ internal void RestoreDispatchState(in DispatchState dispatchState) // See src\inc\corexcep.h's EXCEPTION_COMPLUS definition: private const int _COMPlusExceptionCode = unchecked((int)0xe0434352); // Win32 exception code for COM+ exceptions - private object? SerializationWatsonBuckets => _watsonBuckets; - - private string? SerializationStackTraceString - { - get - { - string? stackTraceString = _stackTraceString; + private bool HasBeenThrown => _stackTrace != null; - if (stackTraceString == null && _stackTrace != null) - { - stackTraceString = GetStackTrace(); - } - - return stackTraceString; - } - } + private object? SerializationWatsonBuckets => _watsonBuckets; // This piece of infrastructure exists to help avoid deadlocks // between parts of CoreLib that might throw an exception while diff --git a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs index c9418961afd9b..428ca4b1d1397 100644 --- a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs +++ b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs @@ -199,6 +199,42 @@ public static bool IsGenericDepthGreaterThan(this TypeDesc type, int depth) return false; } + /// + /// What is the maximum number of steps that need to be taken from this type to its most contained generic type. + /// i.e. + /// SomeGenericType<System.Int32>.Method<System.Int32> => 1 + /// SomeType.Method<System.Int32> => 0 + /// SomeType.Method<List<System.Int32>> => 1 + /// + public static int GetGenericDepth(this MethodDesc method) + { + int genericDepth = method.OwningType.GetGenericDepth(); + foreach (TypeDesc type in method.Instantiation) + { + genericDepth = Math.Max(genericDepth, type.GetGenericDepth()); + } + return genericDepth; + } + + /// + /// Determine if a type has a generic depth greater than a given value + /// + /// + /// + public static bool IsGenericDepthGreaterThan(this MethodDesc method, int depth) + { + if (method.OwningType.IsGenericDepthGreaterThan(depth)) + return true; + + foreach (TypeDesc type in method.Instantiation) + { + if (type.IsGenericDepthGreaterThan(depth)) + return true; + } + + return false; + } + /// /// Determines whether an array type does implements the generic collection interfaces. This is the case /// for multi-dimensional arrays, and arrays of pointers. @@ -508,5 +544,28 @@ public static bool IsNonVersionable(this MetadataType type) { return type.HasCustomAttribute("System.Runtime.Versioning", "NonVersionableAttribute"); } + + /// + /// Return true when the method is marked as non-versionable. Non-versionable methods + /// may be freely inlined into ReadyToRun images even when they don't reside in the + /// same version bubble as the module being compiled. + /// + /// Method to check + /// True when the method is marked as non-versionable, false otherwise. + public static bool IsNonVersionable(this MethodDesc method) + { + return method.HasCustomAttribute("System.Runtime.Versioning", "NonVersionableAttribute"); + } + + /// + /// Returns true if is an actual native entrypoint. + /// There's a distinction between when a method reports it's a PInvoke in the metadata + /// versus how it's treated in the compiler. For many PInvoke methods the compiler will generate + /// an IL body. The methods with an IL method body shouldn't be treated as PInvoke within the compiler. + /// + public static bool IsRawPInvoke(this MethodDesc method) + { + return method.IsPInvoke && (method is Internal.IL.Stubs.PInvokeTargetNativeMethod); + } } } diff --git a/src/coreclr/tools/Common/JitInterface/CallConvHelper.cs b/src/coreclr/tools/Common/JitInterface/CallConvHelper.cs deleted file mode 100644 index ad92b5b36e34c..0000000000000 --- a/src/coreclr/tools/Common/JitInterface/CallConvHelper.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Reflection.Metadata; - -using Internal.TypeSystem; - -namespace Internal.JitInterface -{ - internal static unsafe class CallConvHelper - { - internal static IEnumerable EnumerateCallConvsFromAttribute(CustomAttributeValue attributeWithCallConvsArray) - { - ImmutableArray> callConvArray = default; - foreach (var arg in attributeWithCallConvsArray.NamedArguments) - { - if (arg.Name == "CallConvs") - { - callConvArray = (ImmutableArray>)arg.Value; - } - } - - // No calling convention was specified in the attribute - if (callConvArray.IsDefault) - yield break; - - foreach (CustomAttributeTypedArgument type in callConvArray) - { - if (!(type.Value is DefType defType)) - continue; - - if (defType.Namespace != "System.Runtime.CompilerServices") - continue; - - yield return defType; - } - } - } -} diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index d0cd0f7bc069f..8ec87f59d4a11 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -646,7 +646,7 @@ private CorInfoCallConvExtension GetUnmanagedCallingConventionFromAttribute(Cust bool found = false; bool memberFunctionVariant = false; - foreach (DefType defType in CallConvHelper.EnumerateCallConvsFromAttribute(attributeWithCallConvsArray)) + foreach (DefType defType in attributeWithCallConvsArray.EnumerateCallConvsFromAttribute()) { if (defType.Name == "CallConvMemberFunction") { @@ -1371,7 +1371,7 @@ private static object ResolveTokenInScope(MethodIL methodIL, object typeOrMethod if (typeOrMethodContext is TypeDesc typeContext) { - Debug.Assert(typeContext.HasSameTypeDefinition(owningMethod.OwningType)); + Debug.Assert(typeContext.HasSameTypeDefinition(owningMethod.OwningType) || typeContext.IsArray); typeInst = typeContext.Instantiation; } else @@ -3484,7 +3484,7 @@ private PgoSchemaElem[] getPgoInstrumentationResults(MethodDesc method) return _compilation.ProfileData[method]?.SchemaData; } - public static void ComputeJitPgoInstrumentationSchema(Func objectToHandle, PgoSchemaElem[] pgoResultsSchemas, out PgoInstrumentationSchema[] nativeSchemas, out byte[] instrumentationData) + public static void ComputeJitPgoInstrumentationSchema(Func objectToHandle, PgoSchemaElem[] pgoResultsSchemas, out PgoInstrumentationSchema[] nativeSchemas, out byte[] instrumentationData, Func typeFilter = null) { nativeSchemas = new PgoInstrumentationSchema[pgoResultsSchemas.Length]; MemoryStream msInstrumentationData = new MemoryStream(); @@ -3524,9 +3524,12 @@ public static void ComputeJitPgoInstrumentationSchema(Func objec { foreach (TypeSystemEntityOrUnknown typeVal in typeArray) { - IntPtr ptrVal = IntPtr.Zero; - if (typeVal.AsType != null) + IntPtr ptrVal; + + if (typeVal.AsType != null && (typeFilter == null || typeFilter(typeVal.AsType))) + { ptrVal = (IntPtr)objectToHandle(typeVal.AsType); + } else { // The "Unknown types are the values from 1-33 diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index a14d558df0361..a3af0aa5faa27 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -586,6 +586,9 @@ public override MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(Me // See current interface call resolution for details on how that happens. private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, MetadataType currentType) { + if (currentType.IsInterface) + return null; + MethodDesc methodImpl = FindImplFromDeclFromMethodImpls(currentType, interfaceMethod); if (methodImpl != null) return methodImpl; @@ -723,6 +726,77 @@ private static MethodDesc FindNameSigOverrideForInterfaceMethodRecursive(MethodD } } + public override DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, TypeDesc currentType, out MethodDesc impl) + { + return ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, (MetadataType)currentType, out impl); + } + + private static DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl) + { + TypeDesc interfaceMethodOwningType = interfaceMethod.OwningType; + MetadataType mostSpecificInterface = null; + bool diamondCase = false; + impl = null; + + foreach (MetadataType runtimeInterface in currentType.RuntimeInterfaces) + { + if (runtimeInterface == interfaceMethodOwningType) + { + // Also consider the default interface method implementation on the interface itself + // if we don't have anything else yet + if (mostSpecificInterface == null && !interfaceMethod.IsAbstract) + { + mostSpecificInterface = runtimeInterface; + impl = interfaceMethod; + } + } + else if (Array.IndexOf(runtimeInterface.RuntimeInterfaces, interfaceMethodOwningType) != -1) + { + // This interface might provide a default implementation + MethodImplRecord[] possibleImpls = runtimeInterface.FindMethodsImplWithMatchingDeclName(interfaceMethod.Name); + if (possibleImpls != null) + { + foreach (MethodImplRecord implRecord in possibleImpls) + { + if (implRecord.Decl == interfaceMethod) + { + // This interface provides a default implementation. + // Is it also most specific? + if (mostSpecificInterface == null || Array.IndexOf(runtimeInterface.RuntimeInterfaces, mostSpecificInterface) != -1) + { + mostSpecificInterface = runtimeInterface; + impl = implRecord.Body; + diamondCase = false; + } + else if (Array.IndexOf(mostSpecificInterface.RuntimeInterfaces, runtimeInterface) == -1) + { + diamondCase = true; + } + + break; + } + } + } + } + } + + if (diamondCase) + { + impl = null; + return DefaultInterfaceMethodResolution.Diamond; + } + else if (impl == null) + { + return DefaultInterfaceMethodResolution.None; + } + else if (impl.IsAbstract) + { + return DefaultInterfaceMethodResolution.Reabstraction; + } + + return DefaultInterfaceMethodResolution.DefaultImplementation; + } + public override IEnumerable ComputeAllVirtualSlots(TypeDesc type) { return EnumAllVirtualSlots((MetadataType)type); diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs index 75a95154f66d6..76bb19921aaea 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs @@ -280,6 +280,11 @@ public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(this return type.Context.GetVirtualMethodAlgorithmForType(type).ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethod, type); } + public static DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(this TypeDesc type, MethodDesc interfaceMethod, out MethodDesc implMethod) + { + return type.Context.GetVirtualMethodAlgorithmForType(type).ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, type, out implMethod); + } + /// /// Resolves a virtual method call. /// diff --git a/src/coreclr/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs index 2ccf630949362..e13e61d3862da 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/VirtualMethodAlgorithm.cs @@ -24,6 +24,8 @@ public abstract class VirtualMethodAlgorithm public abstract MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(MethodDesc interfaceMethod, TypeDesc currentType); + public abstract DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, TypeDesc currentType, out MethodDesc impl); + /// /// Resolves a virtual method call. /// @@ -34,4 +36,27 @@ public abstract class VirtualMethodAlgorithm /// public abstract IEnumerable ComputeAllVirtualSlots(TypeDesc type); } + + public enum DefaultInterfaceMethodResolution + { + /// + /// No default implementation was found. + /// + None, + + /// + /// A default implementation was found. + /// + DefaultImplementation, + + /// + /// The implementation was reabstracted. + /// + Reabstraction, + + /// + /// The default implementation conflicts. + /// + Diamond, + } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/MethodExtensions.cs b/src/coreclr/tools/Common/TypeSystem/Interop/CallConvHelpers.cs similarity index 57% rename from src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/MethodExtensions.cs rename to src/coreclr/tools/Common/TypeSystem/Interop/CallConvHelpers.cs index f9b363778a6b0..91a4d0c8da778 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/MethodExtensions.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/CallConvHelpers.cs @@ -1,26 +1,18 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection.Metadata; -using Debug = System.Diagnostics.Debug; +using Internal.TypeSystem.Ecma; -namespace ILCompiler +namespace Internal.TypeSystem { - static class MethodExtensions + internal static unsafe class CallConvHelpers { - /// - /// Returns true if is an actual native entrypoint. - /// There's a distinction between when a method reports it's a PInvoke in the metadata - /// versus how it's treated in the compiler. For many PInvoke methods the compiler will generate - /// an IL body. The methods with an IL method body shouldn't be treated as PInvoke within the compiler. - /// - public static bool IsRawPInvoke(this MethodDesc method) - { - return method.IsPInvoke && (method is Internal.IL.Stubs.PInvokeTargetNativeMethod); - } - /// /// Gets a value indicating whether the method has the SuppressGCTransition attribute /// @@ -58,7 +50,7 @@ public static bool IsSuppressGCTransition(this MethodDesc method) if (unmanagedCallConvAttribute == null) return false; - foreach (DefType defType in Internal.JitInterface.CallConvHelper.EnumerateCallConvsFromAttribute(unmanagedCallConvAttribute.Value)) + foreach (DefType defType in unmanagedCallConvAttribute.Value.EnumerateCallConvsFromAttribute()) { if (defType.Name == "CallConvSuppressGCTransition") { @@ -69,16 +61,31 @@ public static bool IsSuppressGCTransition(this MethodDesc method) return false; } - /// - /// Return true when the method is marked as non-versionable. Non-versionable methods - /// may be freely inlined into ReadyToRun images even when they don't reside in the - /// same version bubble as the module being compiled. - /// - /// Method to check - /// True when the method is marked as non-versionable, false otherwise. - public static bool IsNonVersionable(this MethodDesc method) + public static IEnumerable EnumerateCallConvsFromAttribute(this CustomAttributeValue attributeWithCallConvsArray) { - return method.HasCustomAttribute("System.Runtime.Versioning", "NonVersionableAttribute"); + ImmutableArray> callConvArray = default; + foreach (var arg in attributeWithCallConvsArray.NamedArguments) + { + if (arg.Name == "CallConvs") + { + callConvArray = (ImmutableArray>)arg.Value; + } + } + + // No calling convention was specified in the attribute + if (callConvArray.IsDefault) + yield break; + + foreach (CustomAttributeTypedArgument type in callConvArray) + { + if (!(type.Value is DefType defType)) + continue; + + if (defType.Namespace != "System.Runtime.CompilerServices") + continue; + + yield return defType; + } } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 6299418227bde..bedb1ce62e3a8 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -1,4 +1,4 @@ - + Library ILCompiler.ReadyToRun @@ -186,7 +186,6 @@ - @@ -245,12 +244,12 @@ IL\HelperExtensions.cs + + Interop\CallConvHelpers.cs + JitInterface\TypeString.cs - - JitInterface\CallConvHelper.cs - JitInterface\CorInfoBase.cs diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index ecf16031fe9db..c30fbb254733a 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -245,7 +245,7 @@ private static Version GetICUVersion() int version = 0; try { - Type interopGlobalization = Type.GetType("Interop+Globalization"); + Type interopGlobalization = Type.GetType("Interop+Globalization, System.Private.CoreLib"); if (interopGlobalization != null) { MethodInfo methodInfo = interopGlobalization.GetMethod("GetICUVersion", BindingFlags.NonPublic | BindingFlags.Static); diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 0492071dba4a3..3db188d5a80b6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3657,6 +3657,7 @@ private static void DebugCheckEvent(ref Dictionary? eventsByName #endif private static int GetHelperCallFirstArg(MethodInfo method) { +#if !CORERT // Currently searches for the following pattern // // ... // CAN ONLY BE THE INSTRUCTIONS BELOW @@ -3773,6 +3774,7 @@ private static int GetHelperCallFirstArg(MethodInfo method) } idx++; } +#endif return -1; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Exception.cs b/src/libraries/System.Private.CoreLib/src/System/Exception.cs index 3db9eb77fd5e2..a6760916f9306 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Exception.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Exception.cs @@ -201,6 +201,35 @@ public int HResult partial void RestoreRemoteStackTrace(SerializationInfo info, StreamingContext context); + // Returns the stack trace as a string. If no stack trace is + // available, null is returned. + public virtual string? StackTrace + { + get + { + string? stackTraceString = _stackTraceString; + string? remoteStackTraceString = _remoteStackTraceString; + + // if no stack trace, try to get one + if (stackTraceString != null) + { + return remoteStackTraceString + stackTraceString; + } + if (!HasBeenThrown) + { + return remoteStackTraceString; + } + + return remoteStackTraceString + GetStackTrace(); + } + } + + private string GetStackTrace() + { + // Do not include a trailing newline for backwards compatibility + return new StackTrace(this, fNeedFileInfo: true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); + } + [StackTraceHidden] internal void SetCurrentStackTrace() { @@ -229,5 +258,20 @@ internal void SetRemoteStackTrace(string stackTrace) // would have generated. _remoteStackTraceString = stackTrace + Environment.NewLineConst + SR.Exception_EndStackTraceFromPreviousThrow + Environment.NewLineConst; } + + private string? SerializationStackTraceString + { + get + { + string? stackTraceString = _stackTraceString; + + if (stackTraceString == null && HasBeenThrown) + { + stackTraceString = GetStackTrace(); + } + + return stackTraceString; + } + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index 64269561d7e01..6b0838fc69118 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -142,7 +142,16 @@ public static int SizeOf(Type t) return SizeOfHelper(t, throwIfNotMarshalable: true); } - public static int SizeOf() => SizeOf(typeof(T)); + public static int SizeOf() + { + Type t = typeof(T); + if (t.IsGenericType) + { + throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(T)); + } + + return SizeOfHelper(t, throwIfNotMarshalable: true); + } public static unsafe int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv) { @@ -1153,7 +1162,26 @@ public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t) public static TDelegate GetDelegateForFunctionPointer(IntPtr ptr) { - return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate)); + if (ptr == IntPtr.Zero) + { + throw new ArgumentNullException(nameof(ptr)); + } + + Type t = typeof(TDelegate); + if (t.IsGenericType) + { + throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(TDelegate)); + } + + // For backward compatibility, we allow lookup of existing delegate to + // function pointer mappings using abstract MulticastDelegate type. We will check + // for the non-abstract delegate type later if no existing mapping is found. + if (t.BaseType != typeof(MulticastDelegate) && t != typeof(MulticastDelegate)) + { + throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(TDelegate)); + } + + return (TDelegate)(object)GetDelegateForFunctionPointerInternal(ptr, t); } public static IntPtr GetFunctionPointerForDelegate(Delegate d) diff --git a/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs index 8924a9bfd5b9a..a8fda176114d6 100644 --- a/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs @@ -46,6 +46,8 @@ public DispatchState(MonoStackFrame[]? stackFrames) private int caught_in_unmanaged; #endregion + private bool HasBeenThrown => _traceIPs != null; + public MethodBase? TargetSite { get @@ -58,32 +60,6 @@ public MethodBase? TargetSite } } - public virtual string? StackTrace - { - get - { - string? stackTraceString = _stackTraceString; - string? remoteStackTraceString = _remoteStackTraceString; - - if (stackTraceString != null) - { - return remoteStackTraceString + stackTraceString; - } - if (_traceIPs == null) - { - return remoteStackTraceString; - } - - return remoteStackTraceString + GetStackTrace(); - } - } - - private string GetStackTrace() - { - // Do not include a trailing newline for backwards compatibility - return new StackTrace(this, fNeedFileInfo: true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); - } - internal DispatchState CaptureDispatchState() { MonoStackFrame[]? stackFrames; @@ -160,20 +136,5 @@ private bool CanSetRemoteStackTrace() private static IDictionary CreateDataContainer() => new ListDictionaryInternal(); private static string? SerializationWatsonBuckets => null; - - private string? SerializationStackTraceString - { - get - { - string? stackTraceString = _stackTraceString; - - if (stackTraceString == null && _traceIPs != null) - { - stackTraceString = GetStackTrace(); - } - - return stackTraceString; - } - } } } From 89381757069abf79ac0574c38821d92817cbd37d Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 24 May 2021 21:22:12 -0700 Subject: [PATCH 2/2] Unify Environment.StackTrace --- .../src/System/Environment.CoreCLR.cs | 6 ------ .../System.Private.CoreLib/src/System/Environment.cs | 7 +++++++ .../System.Private.CoreLib/src/System/Environment.Mono.cs | 6 ------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index b375cfddc7ba5..56ac1ec84dfa8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -90,12 +90,6 @@ public static string[] GetCommandLineArgs() // Used by VM internal static string? GetResourceStringLocal(string key) => SR.GetResourceString(key); - public static string StackTrace - { - [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts - get => new StackTrace(true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); - } - /// Gets the number of milliseconds elapsed since the system started. /// A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. public static extern int TickCount diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index 15e19465cae31..6c6c8ced629d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Diagnostics; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; namespace System @@ -203,6 +204,12 @@ public static Version Version } } + public static string StackTrace + { + [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts + get => new StackTrace(true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); + } + private static bool ValidateAndConvertRegistryTarget(EnvironmentVariableTarget target) { Debug.Assert(target != EnvironmentVariableTarget.Process); diff --git a/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs index 69c6bf09ab2dd..43350fe683f2b 100644 --- a/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs @@ -24,12 +24,6 @@ public static extern int ExitCode [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern int GetProcessorCount(); - public static string StackTrace - { - [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts - get => new StackTrace(true).ToString(Diagnostics.StackTrace.TraceFormat.Normal); - } - public static extern int TickCount { [MethodImplAttribute(MethodImplOptions.InternalCall)]