From 2335907893425e67804b92f51d5ec0849a47794a Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 20 Jun 2022 13:21:07 -0700 Subject: [PATCH 1/2] Move allocation of command line argument array to C# Also, avoid redundant allocation of managed string for each command line argument. --- .../src/System/Environment.CoreCLR.cs | 16 +++++++ .../src/System/Environment.NativeAot.cs | 5 ++ src/coreclr/vm/corelib.h | 2 +- src/coreclr/vm/corhost.cpp | 48 +++++-------------- src/coreclr/vm/metasig.h | 2 +- .../src/System/Environment.cs | 5 -- 6 files changed, 35 insertions(+), 43 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index 150348ec16ab55..f689d23e7331a8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -81,6 +81,22 @@ public static string[] GetCommandLineArgs() GetCommandLineArgsNative(); } + private static unsafe string[] InitializeCommandLineArgs(char* exePath, int argc, char** argv) // invoked from VM + { + string[] commandLineArgs = new string[argc + 1]; + string[] mainMethodArgs = new string[argc]; + + commandLineArgs[0] = new string(exePath); + + for (int i = 0; i < mainMethodArgs.Length; i++) + { + commandLineArgs[i + 1] = mainMethodArgs[i] = new string(argv[i]); + } + + s_commandLineArgs = commandLineArgs; + return mainMethodArgs; + } + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Environment_GetProcessorCount")] private static partial int GetProcessorCount(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs index 2573576699927a..e04aeef7117ddb 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs @@ -70,5 +70,10 @@ public static string[] GetCommandLineArgs() Debug.Assert(s_commandLineArgs != null, "VM did not properly setup application."); return (string[])s_commandLineArgs.Clone(); } + + internal static void SetCommandLineArgs(string[] cmdLineArgs) + { + s_commandLineArgs = cmdLineArgs; + } } } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 54eaf1c0d6f60e..cd4995aa321412 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -303,7 +303,7 @@ DEFINE_CLASS(ENUM, System, Enum) DEFINE_CLASS(ENVIRONMENT, System, Environment) DEFINE_METHOD(ENVIRONMENT, GET_RESOURCE_STRING_LOCAL, GetResourceStringLocal, SM_Str_RetStr) -DEFINE_METHOD(ENVIRONMENT, SET_COMMAND_LINE_ARGS, SetCommandLineArgs, SM_ArrStr_RetVoid) +DEFINE_METHOD(ENVIRONMENT, INITIALIZE_COMMAND_LINE_ARGS, InitializeCommandLineArgs, SM_PtrChar_Int_PtrPtrChar_RetArrStr) DEFINE_CLASS(EVENT, Reflection, RuntimeEventInfo) diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index b0c57bf4b17064..cc9fc82db7200f 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -249,7 +249,7 @@ HRESULT CorHost2::ExecuteApplication(LPCWSTR pwzAppFullName, * ActualCmdLine - Foo arg1 arg2. * (Host1) - Full_path_to_Foo arg1 arg2 */ -void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) +static PTRARRAYREF SetCommandLineArgs(PCWSTR pwzAssemblyPath, int argc, PCWSTR* argv) { CONTRACTL { @@ -262,34 +262,17 @@ void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) // Record the command line. SaveManagedCommandLine(pwzAssemblyPath, argc, argv); - // Send the command line to System.Environment. - struct _gc - { - PTRARRAYREF cmdLineArgs; - } gc; - - ZeroMemory(&gc, sizeof(gc)); - GCPROTECT_BEGIN(gc); + PCWSTR exePath = Bundle::AppIsBundle() ? static_cast(Bundle::AppBundle->Path()) : pwzAssemblyPath; - gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass); - OBJECTREF orAssemblyPath = StringObject::NewString(Bundle::AppIsBundle() ? static_cast(Bundle::AppBundle->Path()) : pwzAssemblyPath); - gc.cmdLineArgs->SetAt(0, orAssemblyPath); + PTRARRAYREF result; + PREPARE_NONVIRTUAL_CALLSITE(METHOD__ENVIRONMENT__INITIALIZE_COMMAND_LINE_ARGS); + DECLARE_ARGHOLDER_ARRAY(args, 3); + args[ARGNUM_0] = PTR_TO_ARGHOLDER(exePath); + args[ARGNUM_1] = DWORD_TO_ARGHOLDER(argc); + args[ARGNUM_2] = PTR_TO_ARGHOLDER(argv); + CALL_MANAGED_METHOD_RETREF(result, PTRARRAYREF, args); - for (int i = 0; i < argc; ++i) - { - OBJECTREF argument = StringObject::NewString(argv[i]); - gc.cmdLineArgs->SetAt(i + 1, argument); - } - - MethodDescCallSite setCmdLineArgs(METHOD__ENVIRONMENT__SET_COMMAND_LINE_ARGS); - - ARG_SLOT args[] = - { - ObjToArgSlot(gc.cmdLineArgs), - }; - setCmdLineArgs.Call(args); - - GCPROTECT_END(); + return result; } HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, @@ -356,18 +339,11 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, { GCX_COOP(); - // Here we call the managed method that gets the cmdLineArgs array. - SetCommandLineArgs(pwzAssemblyPath, argc, argv); - PTRARRAYREF arguments = NULL; GCPROTECT_BEGIN(arguments); - arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass); - for (int i = 0; i < argc; ++i) - { - STRINGREF argument = StringObject::NewString(argv[i]); - arguments->SetAt(i, argument); - } + // Here we call the managed method that gets the cmdLineArgs array. + arguments = SetCommandLineArgs(pwzAssemblyPath, argc, argv); if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_Corhost_Swallow_Uncaught_Exceptions)) { diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index f1e7b7fce43eed..9653fc2967e46e 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -490,7 +490,7 @@ DEFINE_METASIG(SM(Str_RetStr, s, s)) DEFINE_METASIG_T(SM(Str_CultureInfo_RetStr, s C(CULTURE_INFO), s)) DEFINE_METASIG_T(SM(Str_CultureInfo_RefBool_RetStr, s C(CULTURE_INFO) r(F), s)) DEFINE_METASIG(SM(PtrPtrChar_PtrPtrChar_Int_RetVoid, P(P(u)) P(P(u)) i, v)) -DEFINE_METASIG(SM(ArrStr_RetVoid, a(s), v)) +DEFINE_METASIG(SM(PtrChar_Int_PtrPtrChar_RetArrStr, P(u) i P(P(u)), a(s))) DEFINE_METASIG(IM(Str_RetVoid, s, v)) DEFINE_METASIG(SM(RefBool_RefBool_RetVoid, r(F) r(F), v)) DEFINE_METASIG_T(IM(Str_Exception_RetVoid, s C(EXCEPTION), v)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index 84eeeb5032f646..976c0110c548cf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -92,11 +92,6 @@ public static string ExpandEnvironmentVariables(string name) private static string[]? s_commandLineArgs; - internal static void SetCommandLineArgs(string[] cmdLineArgs) // invoked from VM - { - s_commandLineArgs = cmdLineArgs; - } - public static string GetFolderPath(SpecialFolder folder) => GetFolderPath(folder, SpecialFolderOption.None); public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option) From e00ae7b7d11fad1da11c99c8a0f0af3f1c7ccf85 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 20 Jun 2022 19:22:44 -0700 Subject: [PATCH 2/2] Fix build break --- .../System.Private.CoreLib/src/System/Environment.CoreCLR.cs | 2 ++ .../System.Private.CoreLib/src/System/Environment.NativeAot.cs | 2 ++ src/libraries/System.Private.CoreLib/src/System/Environment.cs | 2 -- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index f689d23e7331a8..1ab95bc582a8a4 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -61,6 +61,8 @@ public static extern int ExitCode [MethodImpl(MethodImplOptions.InternalCall)] public static extern void FailFast(string? message, Exception? exception, string? errorMessage); + private static string[]? s_commandLineArgs; + public static string[] GetCommandLineArgs() { // There are multiple entry points to a hosted app. The host could diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs index e04aeef7117ddb..c5648c28885a34 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs @@ -65,6 +65,8 @@ internal static void ShutdownCore() public static int TickCount => (int)TickCount64; + private static string[]? s_commandLineArgs; + public static string[] GetCommandLineArgs() { Debug.Assert(s_commandLineArgs != null, "VM did not properly setup application."); diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index 976c0110c548cf..a16af2f212c8a0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -90,8 +90,6 @@ public static string ExpandEnvironmentVariables(string name) return ExpandEnvironmentVariablesCore(name); } - private static string[]? s_commandLineArgs; - public static string GetFolderPath(SpecialFolder folder) => GetFolderPath(folder, SpecialFolderOption.None); public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)