Skip to content

Commit

Permalink
Move allocation of command line argument array to C# (#71021)
Browse files Browse the repository at this point in the history
Also, avoid redundant allocation of managed string for each command line argument.
  • Loading branch information
jkotas authored Jun 21, 2022
1 parent 8a7930e commit 7ab7f83
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -81,6 +83,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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,17 @@ 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.");
return (string[])s_commandLineArgs.Clone();
}

internal static void SetCommandLineArgs(string[] cmdLineArgs)
{
s_commandLineArgs = cmdLineArgs;
}
}
}
2 changes: 1 addition & 1 deletion src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
48 changes: 12 additions & 36 deletions src/coreclr/vm/corhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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<PCWSTR>(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<LPCWSTR>(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,
Expand Down Expand Up @@ -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))
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/metasig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,6 @@ public static string ExpandEnvironmentVariables(string name)
return ExpandEnvironmentVariablesCore(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)
Expand Down

0 comments on commit 7ab7f83

Please sign in to comment.