diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index 9ce8ef00756dd6..e30405481f2ee1 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -214,12 +214,11 @@ The .NET Foundation licenses this file to you under the MIT license.
-
-
+
diff --git a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
index e073885514555f..f58b3405b43d4b 100644
--- a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
+++ b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
@@ -38,6 +38,7 @@
#include "GCMemoryHelpers.h"
#include "GCMemoryHelpers.inl"
#include "yieldprocessornormalized.h"
+#include "RhConfig.h"
COOP_PINVOKE_HELPER(void, RhDebugBreak, ())
{
@@ -422,6 +423,13 @@ COOP_PINVOKE_HELPER(int32_t, RhGetProcessCpuCount, ())
return PalGetProcessCpuCount();
}
+COOP_PINVOKE_HELPER(uint32_t, RhGetKnobValues, (char *** pResultKeys, char *** pResultValues))
+{
+ *pResultKeys = g_pRhConfig->GetKnobNames();
+ *pResultValues = g_pRhConfig->GetKnobValues();
+ return g_pRhConfig->GetKnobCount();
+}
+
#if defined(TARGET_X86) || defined(TARGET_AMD64)
EXTERN_C NATIVEAOT_API void __cdecl RhCpuIdEx(int* cpuInfo, int functionId, int subFunctionId)
{
diff --git a/src/coreclr/nativeaot/Runtime/RhConfig.cpp b/src/coreclr/nativeaot/Runtime/RhConfig.cpp
index 0b965c18994f86..506cf750672bfa 100644
--- a/src/coreclr/nativeaot/Runtime/RhConfig.cpp
+++ b/src/coreclr/nativeaot/Runtime/RhConfig.cpp
@@ -120,14 +120,8 @@ bool RhConfig::Environment::TryGetStringValue(const char* name, char** value)
return true;
}
-struct CompilerEmbeddedSettingsBlob
-{
- uint32_t Size;
- char Data[1];
-};
-
-extern "C" CompilerEmbeddedSettingsBlob g_compilerEmbeddedSettingsBlob;
-extern "C" CompilerEmbeddedSettingsBlob g_compilerEmbeddedKnobsBlob;
+extern "C" RhConfig::Config g_compilerEmbeddedSettingsBlob;
+extern "C" RhConfig::Config g_compilerEmbeddedKnobsBlob;
bool RhConfig::ReadConfigValue(_In_z_ const char *name, uint64_t* pValue, bool decimal)
{
@@ -136,7 +130,7 @@ bool RhConfig::ReadConfigValue(_In_z_ const char *name, uint64_t* pValue, bool d
// Check the embedded configuration
const char *embeddedValue = nullptr;
- if (GetEmbeddedVariable(&g_embeddedSettings, &g_compilerEmbeddedSettingsBlob, name, true, &embeddedValue))
+ if (GetEmbeddedVariable(&g_compilerEmbeddedSettingsBlob, name, true, &embeddedValue))
{
*pValue = strtoull(embeddedValue, NULL, decimal ? 10 : 16);
return true;
@@ -148,7 +142,7 @@ bool RhConfig::ReadConfigValue(_In_z_ const char *name, uint64_t* pValue, bool d
bool RhConfig::ReadKnobUInt64Value(_In_z_ const char *name, uint64_t* pValue)
{
const char *embeddedValue = nullptr;
- if (GetEmbeddedVariable(&g_embeddedKnobs, &g_compilerEmbeddedKnobsBlob, name, false, &embeddedValue))
+ if (GetEmbeddedVariable(&g_compilerEmbeddedKnobsBlob, name, false, &embeddedValue))
{
*pValue = strtoull(embeddedValue, NULL, 10);
return true;
@@ -160,7 +154,7 @@ bool RhConfig::ReadKnobUInt64Value(_In_z_ const char *name, uint64_t* pValue)
bool RhConfig::ReadKnobBooleanValue(_In_z_ const char *name, bool* pValue)
{
const char *embeddedValue = nullptr;
- if (GetEmbeddedVariable(&g_embeddedKnobs, &g_compilerEmbeddedKnobsBlob, name, false, &embeddedValue))
+ if (GetEmbeddedVariable(&g_compilerEmbeddedKnobsBlob, name, false, &embeddedValue))
{
*pValue = strcmp(embeddedValue, "true") == 0;
return true;
@@ -169,29 +163,30 @@ bool RhConfig::ReadKnobBooleanValue(_In_z_ const char *name, bool* pValue)
return false;
}
-bool RhConfig::GetEmbeddedVariable(void *volatile * embeddedSettings, void* compilerEmbeddedSettingsBlob, _In_z_ const char* configName, bool caseSensitive, _Out_ const char** configValue)
+char** RhConfig::GetKnobNames()
{
- // Read the config if we haven't yet
- if (*embeddedSettings == NULL)
- {
- ReadEmbeddedSettings(embeddedSettings, compilerEmbeddedSettingsBlob);
- }
+ return g_compilerEmbeddedKnobsBlob.GetKeys();
+}
- // Config wasn't read or reading failed
- if (*embeddedSettings == CONFIG_INI_NOT_AVAIL)
- {
- return false;
- }
+char** RhConfig::GetKnobValues()
+{
+ return g_compilerEmbeddedKnobsBlob.GetValues();
+}
- const ConfigPair* configPairs = (const ConfigPair*)*embeddedSettings;
+uint32_t RhConfig::GetKnobCount()
+{
+ return g_compilerEmbeddedKnobsBlob.GetCount();
+}
+bool RhConfig::GetEmbeddedVariable(Config* config, _In_z_ const char* configName, bool caseSensitive, _Out_ const char** configValue)
+{
// Find the first name which matches
- for (uint32_t iSettings = 0; iSettings < ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Size; iSettings++)
+ for (uint32_t iSettings = 0; iSettings < config->GetCount(); iSettings++)
{
- if ((caseSensitive && strcmp(configName, configPairs[iSettings].Key) == 0)
- || (!caseSensitive && _stricmp(configName, configPairs[iSettings].Key) == 0))
+ if ((caseSensitive && strcmp(configName, config->GetKeyAt(iSettings)) == 0)
+ || (!caseSensitive && _stricmp(configName, config->GetKeyAt(iSettings)) == 0))
{
- *configValue = configPairs[iSettings].Value;
+ *configValue = config->GetValueAt(iSettings);
return true;
}
}
@@ -200,107 +195,4 @@ bool RhConfig::GetEmbeddedVariable(void *volatile * embeddedSettings, void* comp
return false;
}
-void RhConfig::ReadEmbeddedSettings(void *volatile * embeddedSettings, void* compilerEmbeddedSettingsBlob)
-{
- if (*embeddedSettings == NULL)
- {
- uint32_t size = ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Size;
- char* data = ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Data;
-
- //if reading the file contents failed set embeddedSettings to CONFIG_INI_NOT_AVAIL
- if (size == 0)
- {
- //only set if another thread hasn't initialized the buffer yet, otherwise ignore and let the first setter win
- PalInterlockedCompareExchangePointer(embeddedSettings, CONFIG_INI_NOT_AVAIL, NULL);
-
- return;
- }
-
- ConfigPair* iniBuff = new (nothrow) ConfigPair[size];
- if (iniBuff == NULL)
- {
- //only set if another thread hasn't initialized the buffer yet, otherwise ignore and let the first setter win
- PalInterlockedCompareExchangePointer(embeddedSettings, CONFIG_INI_NOT_AVAIL, NULL);
-
- return;
- }
-
- uint32_t iBuff = 0;
- uint32_t iIniBuff = 0;
- char* currLine;
-
- //while we haven't reached the max number of config pairs, or the end of the file, read the next line
- while (iBuff < size)
- {
- currLine = &data[iBuff];
-
- //find the end of the line
- while ((data[iBuff] != '\0') && (iBuff < size))
- iBuff++;
-
- //parse the line
- //only increment iIniBuff if the parsing succeeded otherwise reuse the config struct
- if (ParseConfigLine(&iniBuff[iIniBuff], currLine))
- {
- iIniBuff++;
- }
-
- //advance to the next line;
- iBuff++;
- }
-
- //if another thread initialized first let the first setter win
- //delete the iniBuff to avoid leaking memory
- if (PalInterlockedCompareExchangePointer(embeddedSettings, iniBuff, NULL) != NULL)
- {
- delete[] iniBuff;
- }
- }
-
- return;
-}
-
-//Parses one line of config and populates values in the passed in configPair
-//returns: true if the parsing was successful, false if the parsing failed.
-//NOTE: if the method fails configPair is left in an uninitialized state
-bool RhConfig::ParseConfigLine(_Out_ ConfigPair* configPair, _In_z_ const char * line)
-{
- uint32_t iLine = 0;
- uint32_t iKey = 0;
- uint32_t iVal = 0;
-
- //while we haven't reached the end of the key signalled by '=', or the end of the line, or the key maxlen
- while (line[iLine] != '=' && line[iLine] != '\0' && iKey < CONFIG_KEY_MAXLEN)
- {
- configPair->Key[iKey++] = line[iLine++];
- }
-
- //if the current char is not '=' we reached the key maxlen, or the line ended return false
- if (line[iLine] != '=')
- {
- return FALSE;
- }
-
- configPair->Key[iKey] = '\0';
-
- //increment to start of the value
- iLine++;
-
- //while we haven't reached the end of the line, or val maxlen
- while (line[iLine] != '\0' && iVal < CONFIG_VAL_MAXLEN)
- {
- configPair->Value[iVal++] = line[iLine++];
- }
-
- //if the current char is not '\0' we didn't reach the end of the line return false
- if (line[iLine] != '\0')
- {
- return FALSE;
- }
-
- configPair->Value[iVal] = '\0';
-
- return TRUE;
-}
-
#endif
diff --git a/src/coreclr/nativeaot/Runtime/RhConfig.h b/src/coreclr/nativeaot/Runtime/RhConfig.h
index a3cd83493cab96..5d56f57cb3b42b 100644
--- a/src/coreclr/nativeaot/Runtime/RhConfig.h
+++ b/src/coreclr/nativeaot/Runtime/RhConfig.h
@@ -18,26 +18,20 @@
class RhConfig
{
-
-#define CONFIG_INI_NOT_AVAIL (void*)0x1 //signal for ini file failed to load
-#define CONFIG_KEY_MAXLEN 50 //arbitrary max length of config keys increase if needed
#define CONFIG_VAL_MAXLEN 16 //64 bit uint in hex
-private:
- struct ConfigPair
+public:
+ struct Config
{
+ uint32_t m_count;
+ char* m_first[];
public:
- char Key[CONFIG_KEY_MAXLEN + 1]; //maxlen + null terminator
- char Value[CONFIG_VAL_MAXLEN + 1]; //maxlen + null terminator
+ uint32_t GetCount() { return m_count; }
+ char* GetKeyAt(int32_t index) { return m_first[index]; }
+ char* GetValueAt(int32_t index) { return m_first[m_count + index]; }
+ char** GetKeys() { return m_first; }
+ char** GetValues() { return &m_first[m_count]; }
};
- // g_embeddedSettings is a buffer of ConfigPair structs embedded in the compiled binary.
- //
- //NOTE: g_embeddedSettings is only set in ReadEmbeddedSettings and must be set atomically only once
- // using PalInterlockedCompareExchangePointer to avoid races when initializing
- void* volatile g_embeddedSettings = NULL;
- void* volatile g_embeddedKnobs = NULL;
-
-public:
class Environment
{
public: // static
@@ -52,6 +46,10 @@ class RhConfig
bool ReadKnobUInt64Value(_In_z_ const char* wszName, uint64_t* pValue);
bool ReadKnobBooleanValue(_In_z_ const char* wszName, bool* pValue);
+ char** GetKnobNames();
+ char** GetKnobValues();
+ uint32_t GetKnobCount();
+
#define DEFINE_VALUE_ACCESSOR(_name, defaultVal) \
uint64_t Get##_name() \
{ \
@@ -99,16 +97,9 @@ class RhConfig
#define CONFIG_FILE_MAXLEN RCV_Count * sizeof(ConfigPair) + 2000
private:
- //Parses one line of config and populates values in the passed in configPair
- //returns: true if the parsing was successful, false if the parsing failed.
- //NOTE: if the method fails configPair is left in an uninitialized state
- bool ParseConfigLine(_Out_ ConfigPair* configPair, _In_z_ const char * line);
-
- void ReadEmbeddedSettings(void *volatile * embeddedSettings, void* compilerEmbeddedSettingsBlob);
-
// Gets a pointer to the embedded configuration value. Memory is held by the callee.
// Returns true if the variable was found, false otherwise
- bool GetEmbeddedVariable(void *volatile * embeddedSettings, void* compilerEmbeddedSettingsBlob, _In_z_ const char* configName, bool caseSensitive, _Out_ const char** configValue);
+ bool GetEmbeddedVariable(Config* config, _In_z_ const char* configName, bool caseSensitive, _Out_ const char** configValue);
uint32_t m_uiConfigValuesRead;
uint64_t m_uiConfigValues[RCV_Count];
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/AppContext.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/AppContext.NativeAot.cs
index 830ae290d5a2c9..535eb123ddf0f3 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/AppContext.NativeAot.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/AppContext.NativeAot.cs
@@ -1,13 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
using System.Runtime;
using System.Runtime.ExceptionServices;
+using System.Text;
namespace System
{
public static partial class AppContext
{
+ private static unsafe Dictionary InitializeDataStore()
+ {
+ uint count = RuntimeImports.RhGetKnobValues(out byte** keys, out byte** values);
+
+ var dataStore = new Dictionary((int)count);
+ for (int i = 0; i < count; i++)
+ {
+ dataStore.Add(
+ Encoding.UTF8.GetString(keys[i], string.strlen(keys[i])),
+ Encoding.UTF8.GetString(values[i], string.strlen(values[i])));
+ }
+
+ return dataStore;
+ }
+
[RuntimeExport("OnFirstChanceException")]
internal static void OnFirstChanceException(object e)
{
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
index 61f8c38b6cb93b..d5c24694eeca05 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
@@ -553,6 +553,10 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
[RuntimeImport(RuntimeLibrary, "RhGetLoadedOSModules")]
internal static extern uint RhGetLoadedOSModules(IntPtr[] resultArray);
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhGetKnobValues")]
+ internal static extern unsafe uint RhGetKnobValues(out byte** keyArray, out byte** valueArray);
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetOSModuleFromPointer")]
internal static extern IntPtr RhGetOSModuleFromPointer(IntPtr pointerVal);
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeConfigurationRootProvider.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeConfigurationRootProvider.cs
index 122067c0587103..9f44f802f3d22b 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeConfigurationRootProvider.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeConfigurationRootProvider.cs
@@ -2,6 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Text;
+
+using ILCompiler.DependencyAnalysis;
+
+using Internal.Text;
namespace ILCompiler
{
@@ -11,47 +16,114 @@ namespace ILCompiler
///
public class RuntimeConfigurationRootProvider : ICompilationRootProvider
{
- private readonly IEnumerable _runtimeOptions;
+ private readonly string _blobName;
+ private readonly IReadOnlyCollection _runtimeOptions;
- public RuntimeConfigurationRootProvider(IEnumerable runtimeOptions)
+ public RuntimeConfigurationRootProvider(string blobName, IReadOnlyCollection runtimeOptions)
{
+ _blobName = blobName;
_runtimeOptions = runtimeOptions;
}
void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)
{
- rootProvider.RootReadOnlyDataBlob(GetRuntimeOptionsBlob(), 4, "Runtime configuration information", "g_compilerEmbeddedSettingsBlob");
+ rootProvider.AddCompilationRoot(new RuntimeConfigurationBlobNode(_blobName, _runtimeOptions), "Runtime configuration");
}
- protected byte[] GetRuntimeOptionsBlob()
+ private sealed class RuntimeConfigurationBlobNode : DehydratableObjectNode, ISymbolDefinitionNode
{
- const int HeaderSize = 4;
+ private readonly string _blobName;
+ private readonly IReadOnlyCollection _runtimeOptions;
+
+ public RuntimeConfigurationBlobNode(string blobName, IReadOnlyCollection runtimeOptions)
+ {
+ _blobName = blobName;
+ _runtimeOptions = runtimeOptions;
+ }
- ArrayBuilder options = default(ArrayBuilder);
+ public int Offset => 0;
- // Reserve space for the header
- options.ZeroExtend(HeaderSize);
+ public override bool IsShareable => false;
- foreach (string option in _runtimeOptions)
- {
- byte[] optionBytes = System.Text.Encoding.ASCII.GetBytes(option);
- options.Append(optionBytes);
+ public override int ClassCode => 7864454;
- // Emit a null to separate the next option
- options.Add(0);
+ public override bool StaticDependenciesAreComputed => true;
+
+ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append(_blobName);
}
- byte[] result = options.ToArray();
+ protected override ObjectNodeSection GetDehydratedSection(NodeFactory factory) => ObjectNodeSection.ReadOnlyDataSection;
+
+ protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
+
+ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relocsOnly = false)
+ {
+ var builder = new ObjectDataBuilder(factory.TypeSystemContext.Target, relocsOnly);
+ builder.AddSymbol(this);
- int length = options.Count - HeaderSize;
+ var settings = new Dictionary();
- // Encode the size of the blob into the header
- result[0] = (byte)length;
- result[1] = (byte)(length >> 8);
- result[2] = (byte)(length >> 0x10);
- result[3] = (byte)(length >> 0x18);
+ // Put values in a dictionary - we expect many "true" strings, for example.
+ var valueDict = new Dictionary();
+ int valueIndex = 0;
+ foreach (string line in _runtimeOptions)
+ {
+ int indexOfEquals = line.IndexOf("=");
+ if (indexOfEquals > 0)
+ {
+ string key = line.Substring(0, indexOfEquals);
+ string value = line.Substring(indexOfEquals + 1);
- return result;
+ if (!valueDict.TryGetValue(value, out ISymbolNode valueNode))
+ {
+ valueNode = factory.ReadOnlyDataBlob(
+ new Utf8String(_blobName + "_value_" + valueIndex++),
+ Utf8NullTerminatedBytes(value),
+ alignment: 1);
+ valueDict.Add(value, valueNode);
+ }
+
+ settings[key] = valueNode;
+ }
+ }
+
+ // The format is:
+ // * Number of entries (T)
+ // * N times pointer to key
+ // * N times pointer to value
+ builder.EmitNaturalInt(settings.Count);
+
+ int i = 0;
+ foreach (string key in settings.Keys)
+ {
+ ISymbolNode node = factory.ReadOnlyDataBlob(
+ new Utf8String(_blobName + "_key_" + i++),
+ Utf8NullTerminatedBytes(key),
+ alignment: 1);
+ builder.EmitPointerReloc(node);
+ }
+
+ foreach (ISymbolNode value in settings.Values)
+ {
+ builder.EmitPointerReloc(value);
+ }
+
+ static byte[] Utf8NullTerminatedBytes(string s)
+ {
+ byte[] result = new byte[Encoding.UTF8.GetByteCount(s) + 1];
+ Encoding.UTF8.GetBytes(s, result);
+ return result;
+ }
+
+ return builder.ToObjectData();
+ }
+
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+ {
+ return _blobName.CompareTo(((RuntimeConfigurationBlobNode)other)._blobName);
+ }
}
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeKnobsRootProvider.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeKnobsRootProvider.cs
deleted file mode 100644
index db1d0236a1556e..00000000000000
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RuntimeKnobsRootProvider.cs
+++ /dev/null
@@ -1,57 +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.Collections.Generic;
-
-namespace ILCompiler
-{
- ///
- /// A root provider that provides a runtime configuration blob that influences runtime behaviors.
- /// See RhConfigValues.h for allowed values.
- ///
- public class RuntimeKnobsRootProvider : ICompilationRootProvider
- {
- private readonly IEnumerable _runtimeKnobs;
-
- public RuntimeKnobsRootProvider(IEnumerable runtimeKnobs)
- {
- _runtimeKnobs = runtimeKnobs;
- }
-
- void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)
- {
- rootProvider.RootReadOnlyDataBlob(GetRuntimeKnobsBlob(), 4, "Runtime configuration knobs", "g_compilerEmbeddedKnobsBlob");
- }
-
- protected byte[] GetRuntimeKnobsBlob()
- {
- const int HeaderSize = 4;
-
- ArrayBuilder options = default(ArrayBuilder);
-
- // Reserve space for the header
- options.ZeroExtend(HeaderSize);
-
- foreach (string option in _runtimeKnobs)
- {
- byte[] optionBytes = System.Text.Encoding.UTF8.GetBytes(option);
- options.Append(optionBytes);
-
- // Emit a null to separate the next option
- options.Add(0);
- }
-
- byte[] result = options.ToArray();
-
- int length = options.Count - HeaderSize;
-
- // Encode the size of the blob into the header
- result[0] = (byte)length;
- result[1] = (byte)(length >> 8);
- result[2] = (byte)(length >> 0x10);
- result[3] = (byte)(length >> 0x18);
-
- return result;
- }
- }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/AppContextInitializerMethod.Sorting.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/AppContextInitializerMethod.Sorting.cs
deleted file mode 100644
index 27d6287aef7e73..00000000000000
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/AppContextInitializerMethod.Sorting.cs
+++ /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.
-
-using Internal.TypeSystem;
-
-using Debug = System.Diagnostics.Debug;
-
-namespace Internal.IL.Stubs.StartupCode
-{
- public partial class AppContextInitializerMethod
- {
- protected override int ClassCode => 15749517;
-
- protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer)
- {
- // Should be a singleton
- Debug.Assert(this == other);
- return 0;
- }
- }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/AppContextInitializerMethod.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/AppContextInitializerMethod.cs
deleted file mode 100644
index 92d9eccdaee950..00000000000000
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/AppContextInitializerMethod.cs
+++ /dev/null
@@ -1,98 +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 Internal.TypeSystem;
-
-namespace Internal.IL.Stubs.StartupCode
-{
- public sealed partial class AppContextInitializerMethod : ILStubMethod
- {
- private TypeDesc _owningType;
- private MethodSignature _signature;
- private IReadOnlyCollection> _switches;
-
- public AppContextInitializerMethod(TypeDesc owningType, IEnumerable args)
- {
- _owningType = owningType;
- var switches = new List>();
-
- foreach (string s in args)
- {
- int index = s.IndexOf('=');
- if (index <= 0)
- throw new ArgumentException($"String '{s}' in unexpected format. Expected 'Key=Value'");
- switches.Add(KeyValuePair.Create(s.Substring(0, index), s.Substring(index + 1)));
- }
-
- _switches = switches;
- }
-
- public override TypeSystemContext Context
- {
- get
- {
- return _owningType.Context;
- }
- }
-
- public override TypeDesc OwningType
- {
- get
- {
- return _owningType;
- }
- }
-
- public override string Name
- {
- get
- {
- return "SetAppContextSwitches";
- }
- }
-
- public override string DiagnosticName
- {
- get
- {
- return "SetAppContextSwitches";
- }
- }
-
- public override MethodIL EmitIL()
- {
- ILEmitter emitter = new ILEmitter();
- ILCodeStream codeStream = emitter.NewCodeStream();
-
- MetadataType appContextType = Context.SystemModule.GetKnownType("System", "AppContext");
- MethodDesc setDataMethod = appContextType.GetKnownMethod("SetData", null);
- ILToken setDataToken = emitter.NewToken(setDataMethod);
-
- foreach (KeyValuePair keyValue in _switches)
- {
- codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(keyValue.Key));
- codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(keyValue.Value));
- codeStream.Emit(ILOpcode.call, setDataToken);
- }
-
- codeStream.Emit(ILOpcode.ret);
-
- return emitter.Link(this);
- }
-
- public override MethodSignature Signature
- {
- get
- {
- _signature ??= new MethodSignature(MethodSignatureFlags.Static, 0,
- Context.GetWellKnownType(WellKnownType.Void),
- TypeDesc.EmptyTypes);
-
- return _signature;
- }
- }
- }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
index 724df1c41ccfcc..dab78aced8a6ec 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
@@ -579,7 +579,6 @@
-
@@ -624,8 +623,6 @@
-
-
diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs b/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
index ff80a245bcea6f..bff1944c3cc9dd 100644
--- a/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
+++ b/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
@@ -88,8 +88,6 @@ internal sealed class ILCompilerRootCommand : RootCommand
new(new[] { "--methodbodyfolding" }, "Fold identical method bodies");
public Option InitAssemblies { get; } =
new(new[] { "--initassembly" }, Array.Empty, "Assembly(ies) with a library initializer");
- public Option AppContextSwitches { get; } =
- new(new[] { "--appcontextswitch" }, Array.Empty, "System.AppContext switches to set (format: 'Key=Value')");
public Option FeatureSwitches { get; } =
new(new[] { "--feature" }, Array.Empty, "Feature switches to apply (format: 'Namespace.Name=[true|false]'");
public Option RuntimeOptions { get; } =
@@ -207,7 +205,6 @@ public ILCompilerRootCommand(string[] args) : base(".NET Native IL Compiler")
AddOption(EmitStackTraceData);
AddOption(MethodBodyFolding);
AddOption(InitAssemblies);
- AddOption(AppContextSwitches);
AddOption(FeatureSwitches);
AddOption(RuntimeOptions);
AddOption(RuntimeKnobs);
diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs
index 36493522a44041..b667245a32b34b 100644
--- a/src/coreclr/tools/aot/ILCompiler/Program.cs
+++ b/src/coreclr/tools/aot/ILCompiler/Program.cs
@@ -41,7 +41,7 @@ public Program(ILCompilerRootCommand command)
}
}
- private List CreateInitializerList(CompilerTypeSystemContext context)
+ private IReadOnlyCollection CreateInitializerList(CompilerTypeSystemContext context)
{
List assembliesWithInitializers = new List();
@@ -55,18 +55,7 @@ private List CreateInitializerList(CompilerTypeSystemContext context
var libraryInitializers = new LibraryInitializers(context, assembliesWithInitializers);
- List initializerList = new List(libraryInitializers.LibraryInitializerMethods);
-
- // If there are any AppContext switches the user wishes to enable, generate code that sets them.
- string[] appContextSwitches = Get(_command.AppContextSwitches);
- if (appContextSwitches.Length > 0)
- {
- MethodDesc appContextInitMethod = new Internal.IL.Stubs.StartupCode.AppContextInitializerMethod(
- context.GeneratedAssembly.GetGlobalModuleType(), appContextSwitches);
- initializerList.Add(appContextInitMethod);
- }
-
- return initializerList;
+ return libraryInitializers.LibraryInitializerMethods;
}
public int Run()
@@ -208,6 +197,8 @@ public int Run()
compilationGroup = new SingleFileCompilationModuleGroup();
}
+ const string settingsBlobName = "g_compilerEmbeddedSettingsBlob";
+ const string knobsBlobName = "g_compilerEmbeddedKnobsBlob";
string[] runtimeOptions = Get(_command.RuntimeOptions);
string[] runtimeKnobs = Get(_command.RuntimeKnobs);
if (nativeLib)
@@ -215,8 +206,8 @@ public int Run()
// Set owning module of generated native library startup method to compiler generated module,
// to ensure the startup method is included in the object file during multimodule mode build
compilationRoots.Add(new NativeLibraryInitializerRootProvider(typeSystemContext.GeneratedAssembly, CreateInitializerList(typeSystemContext)));
- compilationRoots.Add(new RuntimeConfigurationRootProvider(runtimeOptions));
- compilationRoots.Add(new RuntimeKnobsRootProvider(runtimeKnobs));
+ compilationRoots.Add(new RuntimeConfigurationRootProvider(settingsBlobName, runtimeOptions));
+ compilationRoots.Add(new RuntimeConfigurationRootProvider(knobsBlobName, runtimeKnobs));
compilationRoots.Add(new ExpectedIsaFeaturesRootProvider(instructionSetSupport));
if (SplitExeInitialization)
{
@@ -226,8 +217,8 @@ public int Run()
else if (entrypointModule != null)
{
compilationRoots.Add(new MainMethodRootProvider(entrypointModule, CreateInitializerList(typeSystemContext), generateLibraryAndModuleInitializers: !SplitExeInitialization));
- compilationRoots.Add(new RuntimeConfigurationRootProvider(runtimeOptions));
- compilationRoots.Add(new RuntimeKnobsRootProvider(runtimeKnobs));
+ compilationRoots.Add(new RuntimeConfigurationRootProvider(settingsBlobName, runtimeOptions));
+ compilationRoots.Add(new RuntimeConfigurationRootProvider(knobsBlobName, runtimeKnobs));
compilationRoots.Add(new ExpectedIsaFeaturesRootProvider(instructionSetSupport));
if (SplitExeInitialization)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.cs
index 534922c8c24f37..9023a33944b2f9 100644
--- a/src/libraries/System.Private.CoreLib/src/System/AppContext.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.cs
@@ -15,7 +15,11 @@ namespace System
{
public static partial class AppContext
{
- private static Dictionary? s_dataStore;
+ private static Dictionary? s_dataStore
+#if NATIVEAOT
+ = InitializeDataStore()
+#endif
+ ;
private static Dictionary? s_switches;
private static string? s_defaultBaseDirectory;