Move AppDomain local data store to AppContext and cleanup AppContext (#21180)
authorJan Kotas <jkotas@microsoft.com>
Sat, 24 Nov 2018 14:59:54 +0000 (06:59 -0800)
committerGitHub <noreply@github.com>
Sat, 24 Nov 2018 14:59:54 +0000 (06:59 -0800)
Contributes to #21028

20 files changed:
src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs
src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs
src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs
src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs
src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs
src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs [new file with mode: 0644]
src/System.Private.CoreLib/src/System/AppContext/AppContext.cs
src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.CoreClrOverrides.cs [deleted file]
src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.Defaults.Central.cs [deleted file]
src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.Defaults.cs [deleted file]
src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.cs [deleted file]
src/System.Private.CoreLib/src/System/AppContext/AppContextSwitches.cs [deleted file]
src/System.Private.CoreLib/src/System/AppDomain.cs
src/System.Private.CoreLib/src/System/Resources/ResourceManager.cs
src/vm/mscorlib.h
src/vm/object.h

index c62827d..88f9062 100644 (file)
   </ItemGroup>
   <ItemGroup>
     <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContext.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContextSwitches.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.CoreClrOverrides.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.Defaults.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.Defaults.Central.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Object.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Array.cs" />
     <Compile Include="$(BclSourcesRoot)\System\ThrowHelper.cs" />
index ec25efb..3b1eaaa 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Int64.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\IntPtr.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Lazy.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\LocalAppContextSwitches.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\LocalAppContextSwitches.Common.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Marvin.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Marvin.OrdinalIgnoreCase.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Math.cs" />
index 7b8898e..cba324c 100644 (file)
@@ -1919,9 +1919,9 @@ namespace System.Diagnostics.Tracing
 #endif // FEATURE_MANAGED_ETW
                             if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
                     {
-#if (!ES_BUILD_STANDALONE && !ES_BUILD_PN)
+#if !ES_BUILD_STANDALONE
                         // Maintain old behavior - object identity is preserved
-                        if (AppContextSwitches.PreserveEventListnerObjectIdentity)
+                        if (LocalAppContextSwitches.PreserveEventListnerObjectIdentity)
                         {
                             WriteToAllListeners(
                                 eventId: eventId,
index c747f98..9d1cdf1 100644 (file)
@@ -2134,7 +2134,7 @@ namespace System.Globalization
         // Date separator (derived from short date format)
         internal string DateSeparator(CalendarId calendarId)
         {
-            if (calendarId == CalendarId.JAPAN && !AppContextSwitches.EnforceLegacyJapaneseDateParsing)
+            if (calendarId == CalendarId.JAPAN && !LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing)
             {
                 // The date separator is derived from the default short date pattern. So far this pattern is using
                 // '/' as date separator when using the Japanese calendar which make the formatting and parsing work fine.
index b0c6342..0357086 100644 (file)
@@ -655,7 +655,7 @@ namespace System
                         int year = cal.GetYear(dateTime);
                         tokenLen = ParseRepeatPattern(format, i, ch);
                         if (isJapaneseCalendar &&
-                            !AppContextSwitches.FormatJapaneseFirstYearAsANumber &&
+                            !LocalAppContextSwitches.FormatJapaneseFirstYearAsANumber &&
                             year == 1 &&
                             ((i + tokenLen < format.Length && format[i + tokenLen] == DateTimeFormatInfoScanner.CJKYearSuff[0]) ||
                             (i + tokenLen < format.Length - 1 && format[i + tokenLen] == '\'' && format[i + tokenLen + 1] == DateTimeFormatInfoScanner.CJKYearSuff[0])))
index a2665e4..ca6809a 100644 (file)
@@ -2336,7 +2336,7 @@ namespace System.Globalization
                 InsertHash(temp, CJKMinuteSuff, TokenType.SEP_MinuteSuff, 0);
                 InsertHash(temp, CJKSecondSuff, TokenType.SEP_SecondSuff, 0);
 
-                if (!AppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == CalendarId.JAPAN)
+                if (!LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == CalendarId.JAPAN)
                 {
                     // We need to support parsing the dates has the start of era symbol which means it is year 1 in the era.
                     // The start of era symbol has to be followed by the year symbol suffix, otherwise it would be invalid date.
@@ -2650,7 +2650,7 @@ namespace System.Globalization
             // Allow the parser to recognize the case when having some date part followed by JapaneseEraStart "\u5143"
             // without spaces in between. e.g. Era name followed by \u5143 in the date formats ggy.
             // Also, allow recognizing the year suffix symbol "\u5e74" followed the JapaneseEraStart "\u5143"
-            if (!AppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == CalendarId.JAPAN &&
+            if (!LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == CalendarId.JAPAN &&
                 (
                     // something like ggy, era followed by year and the year is specified using the JapaneseEraStart "\u5143"
                     nextCh == JapaneseEraStart[0] ||
index 66d2ba6..c33e5b5 100644 (file)
@@ -3836,7 +3836,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // ParseJapaneseEraStart will be called when parsing the year number. We can have dates which not listing
             // the year as a number and listing it as JapaneseEraStart symbol (which means year 1).
             // This will be legitimate date to recognize.
-            if (AppContextSwitches.EnforceLegacyJapaneseDateParsing || dtfi.Calendar.ID != CalendarId.JAPAN || !str.GetNext())
+            if (LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing || dtfi.Calendar.ID != CalendarId.JAPAN || !str.GetNext())
                 return false;
 
             if (str.m_current != DateTimeFormatInfo.JapaneseEraStart[0])
index 34206b3..ebe6892 100644 (file)
@@ -153,7 +153,7 @@ namespace System.Globalization
                         {
                             return m_EraInfo[i].yearOffset;
                         }
-                        else if (!AppContextSwitches.EnforceJapaneseEraYearRanges)
+                        else if (!LocalAppContextSwitches.EnforceJapaneseEraYearRanges)
                         {
                             // If we got the year number exceeding the era max year number, this still possible be valid as the date can be created before
                             // introducing new eras after the era we are checking. we'll loop on the eras after the era we have and ensure the year
diff --git a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs
new file mode 100644 (file)
index 0000000..521848f
--- /dev/null
@@ -0,0 +1,39 @@
+// 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;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    // Helper method for local caching of compatibility quirks. Keep this lean and simple - this file is included into
+    // every framework assembly that implements any compatibility quirks.
+    internal static partial class LocalAppContextSwitches
+    {
+        // Returns value of given switch using provided cache.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static bool GetCachedSwitchValue(string switchName, ref int cachedSwitchValue)
+        {
+            // The cached switch value has 3 states: 0 - unknown, 1 - true, -1 - false
+            if (cachedSwitchValue < 0) return false;
+            if (cachedSwitchValue > 0) return true;
+
+            return GetCachedSwitchValueInternal(switchName, ref cachedSwitchValue);
+        }
+
+        private static bool GetCachedSwitchValueInternal(string switchName, ref int cachedSwitchValue)
+        {
+            bool isSwitchEnabled;
+            AppContext.TryGetSwitch(switchName, out isSwitchEnabled);
+
+            AppContext.TryGetSwitch(@"TestSwitch.LocalAppContext.DisableCaching", out bool disableCaching);
+            if (!disableCaching)
+            {
+                cachedSwitchValue = isSwitchEnabled ? 1 /*true*/ : -1 /*false*/;
+            }
+
+            return isSwitchEnabled;
+        }
+    }
+}
diff --git a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.cs
new file mode 100644 (file)
index 0000000..8194f87
--- /dev/null
@@ -0,0 +1,51 @@
+// 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;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    internal static partial class LocalAppContextSwitches
+    {
+        private static int s_enforceJapaneseEraYearRanges;
+        public static bool EnforceJapaneseEraYearRanges
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                return GetCachedSwitchValue("Switch.System.Globalization.EnforceJapaneseEraYearRanges", ref s_enforceJapaneseEraYearRanges);
+            }
+        }
+
+        private static int s_formatJapaneseFirstYearAsANumber;
+        public static bool FormatJapaneseFirstYearAsANumber
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                return GetCachedSwitchValue("Switch.System.Globalization.FormatJapaneseFirstYearAsANumber", ref s_formatJapaneseFirstYearAsANumber);
+            }
+        }
+        private static int s_enforceLegacyJapaneseDateParsing;
+        public static bool EnforceLegacyJapaneseDateParsing
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                return GetCachedSwitchValue("Switch.System.Globalization.EnforceLegacyJapaneseDateParsing", ref s_enforceLegacyJapaneseDateParsing);
+            }
+        }
+
+        private static int s_preserveEventListnerObjectIdentity;
+        public static bool PreserveEventListnerObjectIdentity
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                return GetCachedSwitchValue("Switch.System.Diagnostics.EventSource.PreserveEventListnerObjectIdentity", ref s_preserveEventListnerObjectIdentity);
+            }
+        }
+    }
+}
index 3e192d5..3fe3909 100644 (file)
@@ -7,29 +7,20 @@ using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
 using System.Runtime.Versioning;
+using System.Threading;
 
 namespace System
 {
     public static class AppContext
     {
-        [Flags]
-        private enum SwitchValueState
-        {
-            HasFalseValue = 0x1,
-            HasTrueValue = 0x2,
-            HasLookedForOverride = 0x4,
-            UnknownValue = 0x8 // Has no default and could not find an override
-        }
-        private static readonly Dictionary<string, SwitchValueState> s_switchMap = new Dictionary<string, SwitchValueState>();
+        private static Dictionary<string, object> s_dataStore = new Dictionary<string, object>();
+        private static Dictionary<string, bool> s_switches;
 
         static AppContext()
         {
             // Unloading event must happen before ProcessExit event
             AppDomain.CurrentDomain.ProcessExit += OnUnloading;
             AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
-
-            // populate the AppContext with the default set of values
-            AppContextDefaultValues.PopulateDefaultValues();
         }
 
         public static string BaseDirectory
@@ -38,7 +29,7 @@ namespace System
             {
                 // The value of APP_CONTEXT_BASE_DIRECTORY key has to be a string and it is not allowed to be any other type. 
                 // Otherwise the caller will get invalid cast exception
-                string baseDirectory = (string)AppDomain.CurrentDomain.GetData("APP_CONTEXT_BASE_DIRECTORY");
+                string baseDirectory = (string)GetData("APP_CONTEXT_BASE_DIRECTORY");
                 if (baseDirectory != null)
                     return baseDirectory;
 
@@ -62,12 +53,26 @@ namespace System
 
         public static object GetData(string name)
         {
-            return AppDomain.CurrentDomain.GetData(name);
+            if (name == null)
+                throw new ArgumentNullException(nameof(name));
+
+            object data;
+            lock (s_dataStore)
+            {
+                s_dataStore.TryGetValue(name, out data);
+            }
+            return data;
         }
 
         public static void SetData(string name, object data)
         {
-            AppDomain.CurrentDomain.SetData(name, data);
+            if (name == null)
+                throw new ArgumentNullException(nameof(name));
+
+            lock (s_dataStore)
+            {
+                s_dataStore[name] = data;
+            }
         }
 
         public static event UnhandledExceptionEventHandler UnhandledException
@@ -116,7 +121,6 @@ namespace System
             }
         }
 
-        #region Switch APIs
         /// <summary>
         /// Try to get the value of the switch.
         /// </summary>
@@ -130,88 +134,24 @@ namespace System
             if (switchName.Length == 0)
                 throw new ArgumentException(SR.Argument_EmptyName, nameof(switchName));
 
-            // By default, the switch is not enabled.
-            isEnabled = false;
-
-            SwitchValueState switchValue;
-            lock (s_switchMap)
+            if (s_switches != null)
             {
-                if (s_switchMap.TryGetValue(switchName, out switchValue))
+                lock (s_switches)
                 {
-                    // The value is in the dictionary. 
-                    // There are 3 cases here:
-                    // 1. The value of the switch is 'unknown'. This means that the switch name is not known to the system (either via defaults or checking overrides).
-                    //    Example: This is the case when, during a servicing event, a switch is added to System.Xml which ships before mscorlib. The value of the switch
-                    //             Will be unknown to mscorlib.dll and we want to prevent checking the overrides every time we check this switch
-                    // 2. The switch has a valid value AND we have read the overrides for it
-                    //    Example: TryGetSwitch is called for a switch set via SetSwitch
-                    // 3. The switch has the default value and we need to check for overrides
-                    //    Example: TryGetSwitch is called for the first time for a switch that has a default value 
-
-                    // 1. The value is unknown
-                    if (switchValue == SwitchValueState.UnknownValue)
-                    {
-                        isEnabled = false;
-                        return false;
-                    }
-
-                    // We get the value of isEnabled from the value that we stored in the dictionary
-                    isEnabled = (switchValue & SwitchValueState.HasTrueValue) == SwitchValueState.HasTrueValue;
-
-                    // 2. The switch has a valid value AND we have checked for overrides
-                    if ((switchValue & SwitchValueState.HasLookedForOverride) == SwitchValueState.HasLookedForOverride)
-                    {
+                    if (s_switches.TryGetValue(switchName, out isEnabled))
                         return true;
-                    }
-
-                    // 3. The switch has a valid value, but we need to check for overrides.
-                    // Regardless of whether or not the switch has an override, we need to update the value to reflect
-                    // the fact that we checked for overrides. 
-                    bool overrideValue;
-                    if (AppContextDefaultValues.TryGetSwitchOverride(switchName, out overrideValue))
-                    {
-                        // we found an override!
-                        isEnabled = overrideValue;
-                    }
-
-                    // Update the switch in the dictionary to mark it as 'checked for override'
-                    s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
-                                                | SwitchValueState.HasLookedForOverride;
-
-                    return true;
                 }
-                else
-                {
-                    // The value is NOT in the dictionary
-                    // In this case we need to see if we have an override defined for the value.
-                    // There are 2 cases:
-                    // 1. The value has an override specified. In this case we need to add the value to the dictionary 
-                    //    and mark it as checked for overrides
-                    //    Example: In a servicing event, System.Xml introduces a switch and an override is specified.
-                    //             The value is not found in mscorlib (as System.Xml ships independent of mscorlib)
-                    // 2. The value does not have an override specified
-                    //    In this case, we want to capture the fact that we looked for a value and found nothing by adding 
-                    //    an entry in the dictionary with the 'sentinel' value of 'SwitchValueState.UnknownValue'.
-                    //    Example: This will prevent us from trying to find overrides for values that we don't have in the dictionary
-
-                    // 1. The value has an override specified.
-                    bool overrideValue;
-                    if (AppContextDefaultValues.TryGetSwitchOverride(switchName, out overrideValue))
-                    {
-                        isEnabled = overrideValue;
-
-                        // Update the switch in the dictionary to mark it as 'checked for override'
-                        s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
-                                                    | SwitchValueState.HasLookedForOverride;
-
-                        return true;
-                    }
+            }
 
-                    // 2. The value does not have an override.
-                    s_switchMap[switchName] = SwitchValueState.UnknownValue;
-                }
+            string value = GetData(switchName) as string;
+            if (value != null)
+            {
+                if (bool.TryParse(value, out isEnabled))
+                    return true;
             }
-            return false; // we did not find a value for the switch
+
+            isEnabled = false;
+            return false;
         }
 
         /// <summary>
@@ -226,25 +166,16 @@ namespace System
             if (switchName.Length == 0)
                 throw new ArgumentException(SR.Argument_EmptyName, nameof(switchName));
 
-            SwitchValueState switchValue = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
-                                            | SwitchValueState.HasLookedForOverride;
-
-            lock (s_switchMap)
+            if (s_switches == null)
             {
-                // Store the new value and the fact that we checked in the dictionary
-                s_switchMap[switchName] = switchValue;
+                // Compatibility switches are rarely used. Initialize the Dictionary lazily
+                Interlocked.CompareExchange(ref s_switches, new Dictionary<string, bool>(), null); 
             }
-        }
 
-        /// <summary>
-        /// This method is going to be called from the AppContextDefaultValues class when setting up the 
-        /// default values for the switches. !!!! This method is called during the static constructor so it does not
-        /// take a lock !!!! If you are planning to use this outside of that, please ensure proper locking.
-        /// </summary>
-        internal static void DefineSwitchDefault(string switchName, bool isEnabled)
-        {
-            s_switchMap[switchName] = isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue;
+            lock (s_switches)
+            {
+                s_switches[switchName] = isEnabled;
+            }
         }
-        #endregion
     }
 }
diff --git a/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.CoreClrOverrides.cs b/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.CoreClrOverrides.cs
deleted file mode 100644 (file)
index 89893c6..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-namespace System
-{
-    internal static partial class AppContextDefaultValues
-    {
-        static partial void TryGetSwitchOverridePartial(string switchName, ref bool overrideFound, ref bool overrideValue)
-        {
-            overrideFound = false;
-            overrideValue = false;
-
-            string value = AppContext.GetData(switchName) as string;
-            if (value != null)
-            {
-                overrideFound = bool.TryParse(value, out overrideValue);
-            }
-        }
-    }
-}
diff --git a/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.Defaults.Central.cs b/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.Defaults.Central.cs
deleted file mode 100644 (file)
index 92c9917..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-
-//
-// This file is used to provide an implementation for defining a default value
-// This should be compiled only in mscorlib where the AppContext class is available
-//
-
-namespace System
-{
-    internal static partial class AppContextDefaultValues
-    {
-        /// <summary>
-        /// This method allows reading the override for a switch. 
-        /// The implementation is platform specific
-        /// </summary>
-        public static bool TryGetSwitchOverride(string switchName, out bool overrideValue)
-        {
-            // The default value for a switch is 'false'
-            overrideValue = false;
-
-            // Read the override value
-            bool overrideFound = false;
-
-            // This partial method will be removed if there are no implementations of it.
-            TryGetSwitchOverridePartial(switchName, ref overrideFound, ref overrideValue);
-
-            return overrideFound;
-        }
-    }
-}
diff --git a/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.Defaults.cs b/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.Defaults.cs
deleted file mode 100644 (file)
index 4611019..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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;
-
-namespace System
-{
-    internal static partial class AppContextDefaultValues
-    {
-        internal static readonly string SwitchNoAsyncCurrentCulture = "Switch.System.Globalization.NoAsyncCurrentCulture";
-        internal static readonly string SwitchEnforceJapaneseEraYearRanges = "Switch.System.Globalization.EnforceJapaneseEraYearRanges";
-        internal static readonly string SwitchFormatJapaneseFirstYearAsANumber = "Switch.System.Globalization.FormatJapaneseFirstYearAsANumber";
-        internal static readonly string SwitchEnforceLegacyJapaneseDateParsing = "Switch.System.Globalization.EnforceLegacyJapaneseDateParsing";
-        internal static readonly string SwitchPreserveEventListnerObjectIdentity = "Switch.System.Diagnostics.EventSource.PreserveEventListnerObjectIdentity";
-
-        // This is a partial method. Platforms can provide an implementation of it that will set override values
-        // from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls
-        // to it from the code
-        // We are going to have an implementation of this method for the Desktop platform that will read the overrides from app.config, registry and
-        // the shim database. Additional implementation can be provided for other platforms.
-        static partial void PopulateOverrideValuesPartial();
-
-        static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version)
-        {
-            // When defining a new switch  you should add it to the last known version.
-            // For instance, if you are adding a switch in .NET 4.6 (the release after 4.5.2) you should defined your switch
-            // like this:
-            //    if (version <= 40502) ...
-            // This ensures that all previous versions of that platform (up-to 4.5.2) will get the old behavior by default
-            // NOTE: When adding a default value for a switch please make sure that the default value is added to ALL of the existing platforms!
-            // NOTE: When adding a new if statement for the version please ensure that ALL previous switches are enabled (ie. don't use else if)
-            switch (platformIdentifier)
-            {
-                case ".NETCore":
-                case ".NETFramework":
-                    {
-                        if (version <= 40502)
-                        {
-                            AppContext.DefineSwitchDefault(SwitchNoAsyncCurrentCulture, true);
-                        }
-
-                        break;
-                    }
-                case "WindowsPhone":
-                case "WindowsPhoneApp":
-                    {
-                        if (version <= 80100)
-                        {
-                            AppContext.DefineSwitchDefault(SwitchNoAsyncCurrentCulture, true);
-                        }
-                        break;
-                    }
-            }
-
-            // At this point we should read the overrides if any are defined
-            PopulateOverrideValuesPartial();
-        }
-    }
-}
diff --git a/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.cs b/src/System.Private.CoreLib/src/System/AppContext/AppContextDefaultValues.cs
deleted file mode 100644 (file)
index bfbb989..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-// 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;
-using System.Collections.Generic;
-
-namespace System
-{
-    internal static partial class AppContextDefaultValues
-    {
-        public static void PopulateDefaultValues()
-        {
-            string platformIdentifier, profile;
-            int version;
-
-            ParseTargetFrameworkName(out platformIdentifier, out profile, out version);
-
-            // Call into each library to populate their default switches
-            PopulateDefaultValuesPartial(platformIdentifier, profile, version);
-        }
-
-        /// <summary>
-        /// We have this separate method for getting the parsed elements out of the TargetFrameworkName so we can
-        /// more easily support this on other platforms.
-        /// </summary>
-        private static void ParseTargetFrameworkName(out string identifier, out string profile, out int version)
-        {
-            string targetFrameworkMoniker = AppContext.TargetFrameworkName;
-
-            if (!TryParseFrameworkName(targetFrameworkMoniker, out identifier, out version, out profile))
-            {
-                // If we can't parse the TFM or we don't have a TFM, default to latest behavior for all 
-                // switches (ie. all of them false).
-                // If we want to use the latest behavior it is enough to set the value of the switch to string.Empty.
-                // When the get to the caller of this method (PopulateDefaultValuesPartial) we are going to use the 
-                // identifier we just set to decide which switches to turn on. By having an empty string as the 
-                // identifier we are simply saying -- don't turn on any switches, and we are going to get the latest
-                // behavior for all the switches
-                identifier = string.Empty;
-            }
-        }
-
-        // This code was a constructor copied from the FrameworkName class, which is located in System.dll.
-        // Parses strings in the following format: "<identifier>, Version=[v|V]<version>, Profile=<profile>"
-        //  - The identifier and version is required, profile is optional
-        //  - Only three components are allowed.
-        //  - The version string must be in the System.Version format; an optional "v" or "V" prefix is allowed
-        private static bool TryParseFrameworkName(string frameworkName, out string identifier, out int version, out string profile)
-        {
-            // For parsing a target Framework moniker, from the FrameworkName class
-            const char c_componentSeparator = ',';
-            const char c_keyValueSeparator = '=';
-            const char c_versionValuePrefix = 'v';
-            const string c_versionKey = "Version";
-            const string c_profileKey = "Profile";
-
-            identifier = profile = string.Empty;
-            version = 0;
-
-            if (frameworkName == null || frameworkName.Length == 0)
-            {
-                return false;
-            }
-
-            string[] components = frameworkName.Split(c_componentSeparator);
-            version = 0;
-
-            // Identifer and Version are required, Profile is optional.
-            if (components.Length < 2 || components.Length > 3)
-            {
-                return false;
-            }
-
-            //
-            // 1) Parse the "Identifier", which must come first. Trim any whitespace
-            //
-            identifier = components[0].Trim();
-
-            if (identifier.Length == 0)
-            {
-                return false;
-            }
-
-            bool versionFound = false;
-            profile = null;
-
-            // 
-            // The required "Version" and optional "Profile" component can be in any order
-            //
-            for (int i = 1; i < components.Length; i++)
-            {
-                // Get the key/value pair separated by '='
-                string[] keyValuePair = components[i].Split(c_keyValueSeparator);
-
-                if (keyValuePair.Length != 2)
-                {
-                    return false;
-                }
-
-                // Get the key and value, trimming any whitespace
-                string key = keyValuePair[0].Trim();
-                string value = keyValuePair[1].Trim();
-
-                //
-                // 2) Parse the required "Version" key value
-                //
-                if (key.Equals(c_versionKey, StringComparison.OrdinalIgnoreCase))
-                {
-                    versionFound = true;
-
-                    // Allow the version to include a 'v' or 'V' prefix...
-                    Version realVersion = value.Length > 0 && (value[0] == c_versionValuePrefix || value[0] == 'V') ?
-                        Version.Parse(value.AsSpan(1)) :
-                        Version.Parse(value);
-                    // The version class will represent some unset values as -1 internally (instead of 0).
-                    version = realVersion.Major * 10000;
-                    if (realVersion.Minor > 0)
-                        version += realVersion.Minor * 100;
-                    if (realVersion.Build > 0)
-                        version += realVersion.Build;
-                }
-                //
-                // 3) Parse the optional "Profile" key value
-                //
-                else if (key.Equals(c_profileKey, StringComparison.OrdinalIgnoreCase))
-                {
-                    if (!string.IsNullOrEmpty(value))
-                    {
-                        profile = value;
-                    }
-                }
-                else
-                {
-                    return false;
-                }
-            }
-
-            if (!versionFound)
-            {
-                return false;
-            }
-
-            return true;
-        }
-
-        // This is a partial method. Platforms (such as Desktop) can provide an implementation of it that will read override value
-        // from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls
-        // to it from the code
-        static partial void TryGetSwitchOverridePartial(string switchName, ref bool overrideFound, ref bool overrideValue);
-
-        /// This is a partial method. This method is responsible for populating the default values based on a TFM.
-        /// It is partial because each library should define this method in their code to contain their defaults.
-        static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
-    }
-}
diff --git a/src/System.Private.CoreLib/src/System/AppContext/AppContextSwitches.cs b/src/System.Private.CoreLib/src/System/AppContext/AppContextSwitches.cs
deleted file mode 100644 (file)
index 57185ea..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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;
-using System.Runtime.CompilerServices;
-
-namespace System
-{
-    internal static class AppContextSwitches
-    {
-        private static int _noAsyncCurrentCulture;
-        public static bool NoAsyncCurrentCulture
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get
-            {
-                return GetCachedSwitchValue(AppContextDefaultValues.SwitchNoAsyncCurrentCulture, ref _noAsyncCurrentCulture);
-            }
-        }
-
-        private static int _enforceJapaneseEraYearRanges;
-        public static bool EnforceJapaneseEraYearRanges
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get
-            {
-                return GetCachedSwitchValue(AppContextDefaultValues.SwitchEnforceJapaneseEraYearRanges, ref _enforceJapaneseEraYearRanges);
-            }
-        }
-
-        private static int _formatJapaneseFirstYearAsANumber;
-        public static bool FormatJapaneseFirstYearAsANumber
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get
-            {
-                return GetCachedSwitchValue(AppContextDefaultValues.SwitchFormatJapaneseFirstYearAsANumber, ref _formatJapaneseFirstYearAsANumber);
-            }
-        }
-        private static int _enforceLegacyJapaneseDateParsing;
-        public static bool EnforceLegacyJapaneseDateParsing
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get
-            {
-                return GetCachedSwitchValue(AppContextDefaultValues.SwitchEnforceLegacyJapaneseDateParsing, ref _enforceLegacyJapaneseDateParsing);
-            }
-        }
-
-        private static int _preserveEventListnerObjectIdentity;
-        public static bool PreserveEventListnerObjectIdentity
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get
-            {
-                return GetCachedSwitchValue(AppContextDefaultValues.SwitchPreserveEventListnerObjectIdentity, ref _preserveEventListnerObjectIdentity);
-            }
-        }
-
-        //
-        // Implementation details
-        //
-
-        private static bool DisableCaching { get; set; }
-
-        static AppContextSwitches()
-        {
-            bool isEnabled;
-            if (AppContext.TryGetSwitch(@"TestSwitch.LocalAppContext.DisableCaching", out isEnabled))
-            {
-                DisableCaching = isEnabled;
-            }
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool GetCachedSwitchValue(string switchName, ref int switchValue)
-        {
-            if (switchValue < 0) return false;
-            if (switchValue > 0) return true;
-
-            return GetCachedSwitchValueInternal(switchName, ref switchValue);
-        }
-
-        private static bool GetCachedSwitchValueInternal(string switchName, ref int switchValue)
-        {
-            bool isSwitchEnabled;
-            AppContext.TryGetSwitch(switchName, out isSwitchEnabled);
-
-            if (DisableCaching)
-            {
-                return isSwitchEnabled;
-            }
-
-            switchValue = isSwitchEnabled ? 1 /*true*/ : -1 /*false*/;
-            return isSwitchEnabled;
-        }
-    }
-}
index 1d416fe..c1c74d0 100644 (file)
@@ -28,7 +28,6 @@ namespace System
         // of these fields cannot be changed without changing the layout in
         // the EE- AppDomainBaseObject in this case)
 
-        private Dictionary<string, object> _LocalStore;
         public event AssemblyLoadEventHandler AssemblyLoad;
 
         private ResolveEventHandler _TypeResolve;
@@ -142,13 +141,13 @@ namespace System
         /// </summary>
         private void CreateAppDomainManager()
         {
-            string trustedPlatformAssemblies = (string)GetData("TRUSTED_PLATFORM_ASSEMBLIES");
+            string trustedPlatformAssemblies = (string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES");
             if (trustedPlatformAssemblies != null)
             {
-                string platformResourceRoots = (string)GetData("PLATFORM_RESOURCE_ROOTS") ?? string.Empty;
-                string appPaths = (string)GetData("APP_PATHS") ?? string.Empty;
-                string appNiPaths = (string)GetData("APP_NI_PATHS") ?? string.Empty;
-                string appLocalWinMD = (string)GetData("APP_LOCAL_WINMETADATA") ?? string.Empty;
+                string platformResourceRoots = (string)AppContext.GetData("PLATFORM_RESOURCE_ROOTS") ?? string.Empty;
+                string appPaths = (string)AppContext.GetData("APP_PATHS") ?? string.Empty;
+                string appNiPaths = (string)AppContext.GetData("APP_NI_PATHS") ?? string.Empty;
+                string appLocalWinMD = (string)AppContext.GetData("APP_LOCAL_WINMETADATA") ?? string.Empty;
                 SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths, appLocalWinMD);
             }
         }
@@ -215,32 +214,6 @@ namespace System
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern void PublishAnonymouslyHostedDynamicMethodsAssembly(RuntimeAssembly assemblyHandle);
 
-        public void SetData(string name, object data)
-        {
-            if (name == null)
-                throw new ArgumentNullException(nameof(name));
-
-            lock (((ICollection)LocalStore).SyncRoot)
-            {
-                LocalStore[name] = data;
-            }
-        }
-
-        [Pure]
-        public object GetData(string name)
-        {
-            if (name == null)
-                throw new ArgumentNullException(nameof(name));
-
-            object data;
-            lock (((ICollection)LocalStore).SyncRoot)
-            {
-                LocalStore.TryGetValue(name, out data);
-            }
-
-            return data;
-        }
-
         [Obsolete("AppDomain.GetCurrentThreadId has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads). To get a stable identifier for a managed thread, use the ManagedThreadId property on Thread.  http://go.microsoft.com/fwlink/?linkid=14202", false)]
         [DllImport(Interop.Libraries.Kernel32)]
         public static extern int GetCurrentThreadId();
@@ -399,14 +372,6 @@ namespace System
                 null;
         }
 
-        private Dictionary<string, object> LocalStore
-        {
-            get
-            {
-                return _LocalStore ?? (_LocalStore = new Dictionary<string, object>());
-            }
-        }
-
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         private static extern void nSetNativeDllSearchDirectories(string paths);
 
@@ -439,7 +404,7 @@ namespace System
                 {
                     if (propertyNames[i] != null)
                     {
-                        ad.SetData(propertyNames[i], propertyValues[i]);
+                        AppContext.SetData(propertyNames[i], propertyValues[i]);
                     }
                 }
             }
index 6c7f6e7..7c94e12 100644 (file)
@@ -766,7 +766,7 @@ namespace System.Resources
             if (!fUseSatelliteAssemblyResourceLookupUnderAppX)
             {
                 // Check to see if the assembly is under PLATFORM_RESOURCE_ROOTS. If it is, then we should use satellite assembly lookup for it.
-                string platformResourceRoots = (string)(AppDomain.CurrentDomain.GetData("PLATFORM_RESOURCE_ROOTS"));
+                string platformResourceRoots = (string)(AppContext.GetData("PLATFORM_RESOURCE_ROOTS"));
                 if ((platformResourceRoots != null) && (platformResourceRoots != string.Empty))
                 {
                     string resourceAssemblyPath = resourcesAssembly.Location;
index 7b9831c..768bf8f 100644 (file)
@@ -67,7 +67,6 @@ DEFINE_FIELD(ACCESS_VIOLATION_EXCEPTION, TARGET,            _target)
 DEFINE_FIELD(ACCESS_VIOLATION_EXCEPTION, ACCESSTYPE,        _accessType)
 
 DEFINE_CLASS_U(System,                 AppDomain,      AppDomainBaseObject)
-DEFINE_FIELD_U(_LocalStore,                AppDomainBaseObject, m_LocalStore)
 DEFINE_FIELD_U(AssemblyLoad,               AppDomainBaseObject, m_pAssemblyEventHandler)
 DEFINE_FIELD_U(_TypeResolve,               AppDomainBaseObject, m_pTypeEventHandler)
 DEFINE_FIELD_U(_ResourceResolve,           AppDomainBaseObject, m_pResourceEventHandler)
index 1e10756..179d9c4 100644 (file)
@@ -1575,7 +1575,6 @@ class AppDomainBaseObject : public MarshalByRefObjectBaseObject
     // READ ME:
     // Modifying the order or fields of this object may require other changes to the
     //  classlib class definition of this object.
-    OBJECTREF    m_LocalStore;
     OBJECTREF    m_pAssemblyEventHandler; // Delegate for 'loading assembly' event
     OBJECTREF    m_pTypeEventHandler;     // Delegate for 'resolve type' event
     OBJECTREF    m_pResourceEventHandler; // Delegate for 'resolve resource' event