From a63da9e80defe0187d8ee59b9732a978ce4c493e Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Fri, 22 Mar 2019 21:16:41 +0100 Subject: [PATCH] Move Exception to shared partition (#23361) * Move Exception to shared partition * Remove class name caching * Not useful comments removal --- .../System.Private.CoreLib.csproj | 2 +- .../shared/System.Private.CoreLib.Shared.projitems | 1 + .../shared/System/Exception.cs | 196 +++++++++++++ .../System/{Exception.cs => Exception.CoreCLR.cs} | 323 +++------------------ src/vm/mscorlib.h | 2 - src/vm/object.h | 13 +- 6 files changed, 247 insertions(+), 290 deletions(-) create mode 100644 src/System.Private.CoreLib/shared/System/Exception.cs rename src/System.Private.CoreLib/src/System/{Exception.cs => Exception.CoreCLR.cs} (65%) diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index b052272..e75a0fc 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -159,7 +159,7 @@ - + diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 5da4cc2..3cd36e0 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -226,6 +226,7 @@ + diff --git a/src/System.Private.CoreLib/shared/System/Exception.cs b/src/System.Private.CoreLib/shared/System/Exception.cs new file mode 100644 index 0000000..764f36a --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Exception.cs @@ -0,0 +1,196 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Runtime.Serialization; + +namespace System +{ + [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public partial class Exception : ISerializable + { + public Exception() + { + _HResult = HResults.COR_E_EXCEPTION; + } + + public Exception(string message) + : this() + { + _message = message; + } + + // Creates a new Exception. All derived classes should + // provide this constructor. + // Note: the stack trace is not started until the exception + // is thrown + // + public Exception(string message, Exception innerException) + : this() + { + _message = message; + _innerException = innerException; + } + + protected Exception(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException(nameof(info)); + + _message = info.GetString("Message"); // Do not rename (binary serialization) + _data = (IDictionary)(info.GetValueNoThrow("Data", typeof(IDictionary))); // Do not rename (binary serialization) + _innerException = (Exception)(info.GetValue("InnerException", typeof(Exception))); // Do not rename (binary serialization) + _helpURL = info.GetString("HelpURL"); // Do not rename (binary serialization) + _stackTraceString = info.GetString("StackTraceString"); // Do not rename (binary serialization) + _HResult = info.GetInt32("HResult"); // Do not rename (binary serialization) + _source = info.GetString("Source"); // Do not rename (binary serialization) + + RestoreRemoteStackTrace(info, context); + } + + public virtual string Message + { + get + { + return _message ?? SR.Format(SR.Exception_WasThrown, GetClassName()); + } + } + + public virtual IDictionary Data + { + get + { + return _data ?? (_data = CreateDataContainer()); + } + } + + private string GetClassName() => GetType().ToString(); + + // Retrieves the lowest exception (inner most) for the given Exception. + // This will traverse exceptions using the innerException property. + public virtual Exception GetBaseException() + { + Exception inner = InnerException; + Exception back = this; + + while (inner != null) + { + back = inner; + inner = inner.InnerException; + } + + return back; + } + + public Exception InnerException => _innerException; + + // Sets the help link for this exception. + // This should be in a URL/URN form, such as: + // "file:///C:/Applications/Bazzal/help.html#ErrorNum42" + public virtual string HelpLink + { + get + { + return _helpURL; + } + set + { + _helpURL = value; + } + } + + public virtual string Source + { + get + { + return _source ?? (_source = CreateSourceName()); + } + set + { + _source = value; + } + } + + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + if (_source == null) + { + _source = Source; // Set the Source information correctly before serialization + } + + info.AddValue("ClassName", GetClassName(), typeof(string)); // Do not rename (binary serialization) + info.AddValue("Message", _message, typeof(string)); // Do not rename (binary serialization) + info.AddValue("Data", _data, typeof(IDictionary)); // Do not rename (binary serialization) + info.AddValue("InnerException", _innerException, typeof(Exception)); // Do not rename (binary serialization) + info.AddValue("HelpURL", _helpURL, typeof(string)); // Do not rename (binary serialization) + info.AddValue("StackTraceString", SerializationStackTraceString, typeof(string)); // Do not rename (binary serialization) + info.AddValue("RemoteStackTraceString", SerializationRemoteStackTraceString, typeof(string)); // Do not rename (binary serialization) + info.AddValue("RemoteStackIndex", 0, typeof(int)); // Do not rename (binary serialization) + info.AddValue("ExceptionMethod", null, typeof(string)); // Do not rename (binary serialization) + info.AddValue("HResult", _HResult); // Do not rename (binary serialization) + info.AddValue("Source", _source, typeof(string)); // Do not rename (binary serialization) + info.AddValue("WatsonBuckets", SerializationWatsonBuckets, typeof(byte[])); // Do not rename (binary serialization) + } + + public override string ToString() + { + return ToString(true, true); + } + + private string ToString(bool needFileLineInfo, bool needMessage) + { + string s = GetClassName(); + + string message = (needMessage ? Message : null); + if (!string.IsNullOrEmpty(message)) + { + s += ": " + message; + } + + if (_innerException != null) + { + s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + + " " + SR.Exception_EndOfInnerExceptionStack; + } + + string stackTrace = GetStackTrace(needFileLineInfo); + if (stackTrace != null) + { + s += Environment.NewLine + stackTrace; + } + + return s; + } + + protected event EventHandler SerializeObjectState + { + add { throw new PlatformNotSupportedException(SR.PlatformNotSupported_SecureBinarySerialization); } + remove { throw new PlatformNotSupportedException(SR.PlatformNotSupported_SecureBinarySerialization); } + } + + public int HResult + { + get + { + return _HResult; + } + set + { + _HResult = value; + } + } + + // this method is required so Object.GetType is not made virtual by the compiler + // _Exception.GetType() + public new Type GetType() => base.GetType(); + + partial void RestoreRemoteStackTrace(SerializationInfo info, StreamingContext context); + } +} diff --git a/src/System.Private.CoreLib/src/System/Exception.cs b/src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs similarity index 65% rename from src/System.Private.CoreLib/src/System/Exception.cs rename to src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs index c3f9ed7..d7228bd 100644 --- a/src/System.Private.CoreLib/src/System/Exception.cs +++ b/src/System.Private.CoreLib/src/System/Exception.CoreCLR.cs @@ -2,15 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================================= -** -** -** -** Purpose: The base class for all exceptional conditions. -** -** -=============================================================================*/ - using System.Collections; using System.Diagnostics; using System.Reflection; @@ -20,60 +11,11 @@ using System.Runtime.Serialization; namespace System { - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public class Exception : ISerializable + public partial class Exception : ISerializable { - public Exception() + partial void RestoreRemoteStackTrace(SerializationInfo info, StreamingContext context) { - _message = null; - _stackTrace = null; - _dynamicMethods = null; - HResult = HResults.COR_E_EXCEPTION; - _xcode = _COMPlusExceptionCode; - _xptrs = (IntPtr)0; - - // Initialize the WatsonBuckets to be null - _watsonBuckets = null; - - // Initialize the watson bucketing IP - _ipForWatsonBuckets = UIntPtr.Zero; - } - - public Exception(string message) - : this() - { - _message = message; - } - - // Creates a new Exception. All derived classes should - // provide this constructor. - // Note: the stack trace is not started until the exception - // is thrown - // - public Exception(string message, Exception innerException) - : this() - { - _message = message; - _innerException = innerException; - } - - protected Exception(SerializationInfo info, StreamingContext context) - { - if (info == null) - throw new ArgumentNullException(nameof(info)); - - _className = info.GetString("ClassName"); // Do not rename (binary serialization) - _message = info.GetString("Message"); // Do not rename (binary serialization) - _data = (IDictionary)(info.GetValueNoThrow("Data", typeof(IDictionary))); // Do not rename (binary serialization) - _innerException = (Exception)(info.GetValue("InnerException", typeof(Exception))); // Do not rename (binary serialization) - _helpURL = info.GetString("HelpURL"); // Do not rename (binary serialization) - _stackTraceString = info.GetString("StackTraceString"); // Do not rename (binary serialization) _remoteStackTraceString = info.GetString("RemoteStackTraceString"); // Do not rename (binary serialization) - _remoteStackIndex = info.GetInt32("RemoteStackIndex"); // Do not rename (binary serialization) - - HResult = info.GetInt32("HResult"); // Do not rename (binary serialization) - _source = info.GetString("Source"); // Do not rename (binary serialization) // Get the WatsonBuckets that were serialized - this is particularly // done to support exceptions going across AD transitions. @@ -83,10 +25,6 @@ namespace System // get null. _watsonBuckets = (object)info.GetValueNoThrow("WatsonBuckets", typeof(byte[])); // Do not rename (binary serialization) - - if (_className == null || HResult == 0) - throw new SerializationException(SR.Serialization_InsufficientState); - // If we are constructing a new exception after a cross-appdomain call... if (context.State == StreamingContextStates.CrossAppDomain) { @@ -106,38 +44,13 @@ namespace System } } - - public virtual string Message - { - get - { - if (_message == null) - { - if (_className == null) - { - _className = GetClassName(); - } - return SR.Format(SR.Exception_WasThrown, _className); - } - else - { - return _message; - } - } - } - - public virtual IDictionary Data + private IDictionary CreateDataContainer() { - get - { - if (_data == null) - if (IsImmutableAgileException(this)) - _data = new EmptyReadOnlyDictionaryInternal(); - else - _data = new ListDictionaryInternal(); + if (IsImmutableAgileException(this)) + return new EmptyReadOnlyDictionaryInternal(); + else + return new ListDictionaryInternal(); - return _data; - } } [MethodImplAttribute(MethodImplOptions.InternalCall)] @@ -210,40 +123,6 @@ namespace System } #endif // FEATURE_COMINTEROP - private string GetClassName() - { - // Will include namespace but not full instantiation and assembly name. - if (_className == null) - _className = GetType().ToString(); - - return _className; - } - - // Retrieves the lowest exception (inner most) for the given Exception. - // This will traverse exceptions using the innerException property. - // - public virtual Exception GetBaseException() - { - Exception inner = InnerException; - Exception back = this; - - while (inner != null) - { - back = inner; - inner = inner.InnerException; - } - - return back; - } - - // Returns the inner exception contained in this exception - // - public Exception InnerException - { - get { return _innerException; } - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] static private extern IRuntimeMethodInfo GetMethodFromStackTrace(object stackTrace); @@ -320,136 +199,31 @@ namespace System return new StackTrace(e, needFileInfo).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); } - // Sets the help link for this exception. - // This should be in a URL/URN form, such as: - // "file:///C:/Applications/Bazzal/help.html#ErrorNum42" - // Changed to be a read-write String and not return an exception - public virtual string HelpLink - { - get - { - return _helpURL; - } - set - { - _helpURL = value; - } - } - - public virtual string Source + private string CreateSourceName() { - get + StackTrace st = new StackTrace(this, fNeedFileInfo: false); + if (st.FrameCount > 0) { - if (_source == null) - { - StackTrace st = new StackTrace(this, fNeedFileInfo: false); - if (st.FrameCount > 0) - { - StackFrame sf = st.GetFrame(0); - MethodBase method = sf.GetMethod(); + StackFrame sf = st.GetFrame(0); + MethodBase method = sf.GetMethod(); - Module module = method.Module; + Module module = method.Module; - RuntimeModule rtModule = module as RuntimeModule; - - if (rtModule == null) - { - System.Reflection.Emit.ModuleBuilder moduleBuilder = module as System.Reflection.Emit.ModuleBuilder; - if (moduleBuilder != null) - rtModule = moduleBuilder.InternalModule; - else - throw new ArgumentException(SR.Argument_MustBeRuntimeReflectionObject); - } - - _source = rtModule.GetRuntimeAssembly().GetSimpleName(); - } - } + RuntimeModule rtModule = module as RuntimeModule; - return _source; - } - set { _source = value; } - } - - public override string ToString() - { - return ToString(true, true); - } - - private string ToString(bool needFileLineInfo, bool needMessage) - { - string message = (needMessage ? Message : null); - string s; - - if (message == null || message.Length <= 0) - { - s = GetClassName(); - } - else - { - s = GetClassName() + ": " + message; - } - - if (_innerException != null) - { - s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + - " " + SR.Exception_EndOfInnerExceptionStack; - } - - string stackTrace = GetStackTrace(needFileLineInfo); - if (stackTrace != null) - { - s += Environment.NewLine + stackTrace; - } - - return s; - } - - protected event EventHandler SerializeObjectState - { - add { throw new PlatformNotSupportedException(SR.PlatformNotSupported_SecureBinarySerialization); } - remove { throw new PlatformNotSupportedException(SR.PlatformNotSupported_SecureBinarySerialization); } - } - - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - string tempStackTraceString = _stackTraceString; - - if (_stackTrace != null) - { - if (tempStackTraceString == null) + if (rtModule == null) { - tempStackTraceString = GetStackTrace(true, this); - } - if (_exceptionMethod == null) - { - _exceptionMethod = GetExceptionMethodFromStackTrace(); + System.Reflection.Emit.ModuleBuilder moduleBuilder = module as System.Reflection.Emit.ModuleBuilder; + if (moduleBuilder != null) + rtModule = moduleBuilder.InternalModule; + else + throw new ArgumentException(SR.Argument_MustBeRuntimeReflectionObject); } - } - if (_source == null) - { - _source = Source; // Set the Source information correctly before serialization + return rtModule.GetRuntimeAssembly().GetSimpleName(); } - info.AddValue("ClassName", GetClassName(), typeof(string)); // Do not rename (binary serialization) - info.AddValue("Message", _message, typeof(string)); // Do not rename (binary serialization) - info.AddValue("Data", _data, typeof(IDictionary)); // Do not rename (binary serialization) - info.AddValue("InnerException", _innerException, typeof(Exception)); // Do not rename (binary serialization) - info.AddValue("HelpURL", _helpURL, typeof(string)); // Do not rename (binary serialization) - info.AddValue("StackTraceString", tempStackTraceString, typeof(string)); // Do not rename (binary serialization) - info.AddValue("RemoteStackTraceString", _remoteStackTraceString, typeof(string)); // Do not rename (binary serialization) - info.AddValue("RemoteStackIndex", _remoteStackIndex, typeof(int)); // Do not rename (binary serialization) - info.AddValue("ExceptionMethod", null, typeof(string)); // Do not rename (binary serialization) - info.AddValue("HResult", HResult); // Do not rename (binary serialization) - info.AddValue("Source", _source, typeof(string)); // Do not rename (binary serialization) - - // Serialize the Watson bucket details as well - info.AddValue("WatsonBuckets", _watsonBuckets, typeof(byte[])); // Do not rename (binary serialization) + return null; } // This method will clear the _stackTrace of the exception object upon deserialization @@ -604,18 +378,15 @@ namespace System } } - private string _className; //Needed for serialization. private MethodBase _exceptionMethod; //Needed for serialization. internal string _message; private IDictionary _data; private Exception _innerException; private string _helpURL; private object _stackTrace; - [OptionalField] // This isnt present in pre-V4 exception objects that would be serialized. private object _watsonBuckets; private string _stackTraceString; //Needed for serialization. private string _remoteStackTraceString; - private int _remoteStackIndex; #pragma warning disable 414 // Field is not used from managed. // _dynamicMethods is an array of System.Resolver objects, used to keep // DynamicMethodDescs alive for the lifetime of the exception. We do this because @@ -624,31 +395,15 @@ namespace System private object _dynamicMethods; #pragma warning restore 414 - // @MANAGED: HResult is used from within the EE! Rename with care - check VM directory - private int _HResult; // HResult - - public int HResult - { - get - { - return _HResult; - } - set - { - _HResult = value; - } - } - - private string _source; // Mainly used by VB. - // WARNING: Don't delete/rename _xptrs and _xcode - used by functions - // on Marshal class. Native functions are in COMUtilNative.cpp & AppDomain + private string _source; // Mainly used by VB. + private UIntPtr _ipForWatsonBuckets; // Used to persist the IP for Watson Bucketing private IntPtr _xptrs; // Internal EE stuff #pragma warning disable 414 // Field is not used from managed. - private int _xcode; // Internal EE stuff + private int _xcode = _COMPlusExceptionCode; // Internal EE stuff #pragma warning restore 414 - [OptionalField] - private UIntPtr _ipForWatsonBuckets; // Used to persist the IP for Watson Bucketing + // @MANAGED: HResult is used from within the EE! Rename with care - check VM directory + private int _HResult; // HResult // See src\inc\corexcep.h's EXCEPTION_COMPLUS definition: private const int _COMPlusExceptionCode = unchecked((int)0xe0434352); // Win32 exception code for COM+ exceptions @@ -660,18 +415,30 @@ namespace System return ToString(true, true); } - // this method is required so Object.GetType is not made virtual by the compiler - // _Exception.GetType() - public new Type GetType() + internal bool IsTransient { - return base.GetType(); + get + { + return nIsTransient(HResult); + } } - internal bool IsTransient + private string SerializationRemoteStackTraceString => _remoteStackTraceString; + + private object SerializationWatsonBuckets => _watsonBuckets; + + private string SerializationStackTraceString { get { - return nIsTransient(HResult); + string stackTraceString = _stackTraceString; + + if (stackTraceString == null && _stackTrace != null) + { + stackTraceString = GetStackTrace(true, this); + } + + return stackTraceString; } } diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index c54a635..7cb76d3 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -341,7 +341,6 @@ DEFINE_CLASS(EVENT_HANDLERGENERIC, System, EventHandler`1) DEFINE_CLASS(EVENT_INFO, Reflection, EventInfo) DEFINE_CLASS_U(System, Exception, ExceptionObject) -DEFINE_FIELD_U(_className, ExceptionObject, _className) DEFINE_FIELD_U(_exceptionMethod, ExceptionObject, _exceptionMethod) DEFINE_FIELD_U(_message, ExceptionObject, _message) DEFINE_FIELD_U(_data, ExceptionObject, _data) @@ -356,7 +355,6 @@ DEFINE_FIELD_U(_dynamicMethods, ExceptionObject, _dynamicMethods) DEFINE_FIELD_U(_xptrs, ExceptionObject, _xptrs) DEFINE_FIELD_U(_HResult, ExceptionObject, _HResult) DEFINE_FIELD_U(_xcode, ExceptionObject, _xcode) -DEFINE_FIELD_U(_remoteStackIndex, ExceptionObject, _remoteStackIndex) DEFINE_FIELD_U(_ipForWatsonBuckets,ExceptionObject, _ipForWatsonBuckets) DEFINE_CLASS(EXCEPTION, System, Exception) DEFINE_METHOD(EXCEPTION, GET_CLASS_NAME, GetClassName, IM_RetStr) diff --git a/src/vm/object.h b/src/vm/object.h index 9087afa..b4b2363 100644 --- a/src/vm/object.h +++ b/src/vm/object.h @@ -2709,7 +2709,6 @@ public: // If you modify the order of these fields, make sure to update the definition in // BCL for this object. private: - STRINGREF _className; //Needed for serialization. OBJECTREF _exceptionMethod; //Needed for serialization. STRINGREF _message; OBJECTREF _data; @@ -2722,13 +2721,10 @@ private: PTRARRAYREF _dynamicMethods; STRINGREF _source; // Mainly used by VB. - IN_WIN64(void* _xptrs;) - IN_WIN64(UINT_PTR _ipForWatsonBuckets;) // Contains the IP of exception for watson bucketing - INT32 _remoteStackIndex; - INT32 _HResult; - IN_WIN32(void* _xptrs;) + UINT_PTR _ipForWatsonBuckets; // Contains the IP of exception for watson bucketing + void* _xptrs; INT32 _xcode; - IN_WIN32(UINT_PTR _ipForWatsonBuckets;) // Contains the IP of exception for watson bucketing + INT32 _HResult; }; // Defined in Contracts.cs @@ -2757,10 +2753,9 @@ public: private: // keep these in sync with ndp/clr/src/bcl/system/diagnostics/contracts/contractsbcl.cs - IN_WIN64(INT32 _Kind;) STRINGREF _UserMessage; STRINGREF _Condition; - IN_WIN32(INT32 _Kind;) + INT32 _Kind; }; #include "poppack.h" -- 2.7.4