diff --git a/src/coreclr/hosts/corerun/corerun.cpp b/src/coreclr/hosts/corerun/corerun.cpp
index 4e506b95c9746b..60ad5503cfb2ab 100644
--- a/src/coreclr/hosts/corerun/corerun.cpp
+++ b/src/coreclr/hosts/corerun/corerun.cpp
@@ -433,6 +433,7 @@ static int run(const configuration& config)
argv_utf8.get(),
entry_assembly_utf8.c_str(),
(uint32_t*)&exit_code);
+
if (FAILED(result))
{
pal::fprintf(stderr, W("BEGIN: coreclr_execute_assembly failed - Error: 0x%08x\n"), result);
diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp
index 7f156f991c3039..138bd4c6c600cb 100644
--- a/src/coreclr/vm/assembly.cpp
+++ b/src/coreclr/vm/assembly.cpp
@@ -1381,7 +1381,7 @@ void RunManagedStartup()
managedStartup.Call(args);
}
-INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThreads)
+void Assembly::ExecuteMainMethodPre(BOOL waitForOtherThreads)
{
CONTRACTL
{
@@ -1397,9 +1397,6 @@ INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThre
// reset the error code for std C
errno=0;
- HRESULT hr = S_OK;
- INT32 iRetVal = 0;
-
Thread *pThread = GetThread();
MethodDesc *pMeth;
{
@@ -1446,6 +1443,74 @@ INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThre
RunManagedStartup();
+ Thread::CleanUpForManagedThreadInNative(pThread);
+ }
+ }
+
+ //RunMainPost is supposed to be called on the main thread of an EXE,
+ //after that thread has finished doing useful work. It contains logic
+ //to decide when the process should get torn down. So, don't call it from
+ // AppDomain.ExecuteAssembly()
+ if (pMeth) {
+ if (waitForOtherThreads)
+ RunMainPost();
+ }
+ else {
+ StackSString displayName;
+ GetDisplayName(displayName);
+ COMPlusThrowHR(COR_E_MISSINGMETHOD, IDS_EE_FAILED_TO_FIND_MAIN, displayName);
+ }
+
+}
+
+INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThreads)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ ENTRY_POINT;
+ INJECT_FAULT(COMPlusThrowOM());
+ }
+ CONTRACTL_END;
+
+ // reset the error code for std C
+ errno=0;
+
+ HRESULT hr = S_OK;
+ INT32 iRetVal = 0;
+
+ Thread *pThread = GetThread();
+ MethodDesc *pMeth;
+ {
+ // This thread looks like it wandered in -- but actually we rely on it to keep the process alive.
+ pThread->SetBackground(FALSE);
+
+ GCX_COOP();
+
+ pMeth = GetEntryPoint();
+
+ if (pMeth) {
+ {
+#ifdef FEATURE_COMINTEROP
+ GCX_PREEMP();
+
+ Thread::ApartmentState state = Thread::AS_Unknown;
+ state = SystemDomain::GetEntryPointThreadAptState(pMeth->GetMDImport(), pMeth->GetMemberDef());
+ SystemDomain::SetThreadAptState(state);
+#endif // FEATURE_COMINTEROP
+ }
+
+ RunMainPre();
+
+ // Perform additional managed thread initialization.
+ // This would is normally done in the runtime when a managed
+ // thread is started, but is done here instead since the
+ // Main thread wasn't started by the runtime.
+ Thread::InitializationForManagedThreadInNative(pThread);
+
hr = RunMain(pMeth, 1, &iRetVal, stringArgs);
Thread::CleanUpForManagedThreadInNative(pThread);
diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp
index 987b7231b0a40a..4edbdc38d003a2 100644
--- a/src/coreclr/vm/assembly.hpp
+++ b/src/coreclr/vm/assembly.hpp
@@ -251,6 +251,7 @@ class Assembly
//****************************************************************************************
//
+ void ExecuteMainMethodPre(BOOL waitForOtherThreads);
INT32 ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThreads);
//****************************************************************************************
diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp
index bf549e77346b25..3746273c0719f4 100644
--- a/src/coreclr/vm/assemblynative.cpp
+++ b/src/coreclr/vm/assemblynative.cpp
@@ -1170,6 +1170,19 @@ extern "C" void QCALLTYPE AssemblyNative_GetEntryAssembly(QCall::ObjectHandleOnS
END_QCALL;
}
+extern "C" void QCALLTYPE AssemblyNative_UpdateEntryAssembly(QCall::AssemblyHandle assemblyHandle)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ Assembly* pAssembly = assemblyHandle->GetAssembly();
+ PTR_AppDomain pCurDomain = GetAppDomain();
+ pCurDomain->SetRootAssembly(pAssembly);
+
+ END_QCALL;
+}
+
extern "C" void QCALLTYPE AssemblyNative_GetImageRuntimeVersion(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
{
QCALL_CONTRACT;
diff --git a/src/coreclr/vm/assemblynative.hpp b/src/coreclr/vm/assemblynative.hpp
index 80ae3da8c2bd59..11ffdf593e4cc9 100644
--- a/src/coreclr/vm/assemblynative.hpp
+++ b/src/coreclr/vm/assemblynative.hpp
@@ -42,6 +42,8 @@ extern "C" uint32_t QCALLTYPE AssemblyNative_GetAssemblyCount();
extern "C" void QCALLTYPE AssemblyNative_GetEntryAssembly(QCall::ObjectHandleOnStack retAssembly);
+extern "C" void QCALLTYPE AssemblyNative_UpdateEntryAssembly(QCall::AssemblyHandle assemblyHandle);
+
extern "C" void QCALLTYPE AssemblyNative_GetExecutingAssembly(QCall::StackCrawlMarkHandle stackMark, QCall::ObjectHandleOnStack retAssembly);
diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index b85331e00ce8d2..05194fe35e8cd2 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -337,7 +337,10 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId,
if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_Corhost_Swallow_Uncaught_Exceptions))
{
EX_TRY
- DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */);
+ pAssembly->ExecuteMainMethodPre(TRUE /* waitForOtherThreads */);
+ AppDomain *curDomain = SystemDomain::GetCurrentDomain();
+ Assembly *curEntryAssembly = curDomain->GetRootAssembly();
+ DWORD retval = curEntryAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */);
if (pReturnValue)
{
*pReturnValue = retval;
@@ -346,7 +349,10 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId,
}
else
{
- DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */);
+ pAssembly->ExecuteMainMethodPre(TRUE /* waitForOtherThreads */);
+ AppDomain *curDomain = SystemDomain::GetCurrentDomain();
+ Assembly *curEntryAssembly = curDomain->GetRootAssembly();
+ DWORD retval = curEntryAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */);
if (pReturnValue)
{
*pReturnValue = retval;
diff --git a/src/mono/sample/HelloWorld_2/HelloWorld_2.csproj b/src/mono/sample/HelloWorld_2/HelloWorld_2.csproj
new file mode 100644
index 00000000000000..cc052494b398fa
--- /dev/null
+++ b/src/mono/sample/HelloWorld_2/HelloWorld_2.csproj
@@ -0,0 +1,61 @@
+
+
+ Exe
+ $(NetCoreAppCurrent)
+
+ true
+
+
+
+
+
+
+ <_AotOutputType>Library
+ <_AotLibraryFormat>Dylib
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mono/sample/HelloWorld_2/Makefile b/src/mono/sample/HelloWorld_2/Makefile
new file mode 100644
index 00000000000000..17138fc5e87c7d
--- /dev/null
+++ b/src/mono/sample/HelloWorld_2/Makefile
@@ -0,0 +1,34 @@
+TOP=../../../../
+DOTNET:=$(TOP)dotnet.sh
+DOTNET_Q_ARGS=--nologo -v:q -consoleloggerparameters:NoSummary
+
+MONO_CONFIG?=Debug
+MONO_ARCH?=$(shell . $(TOP)eng/common/native/init-os-and-arch.sh && echo $${arch})
+TARGET_OS?=$(shell . $(TOP)eng/common/native/init-os-and-arch.sh && echo $${os})
+AOT?=false
+USE_LLVM?=false
+StripILCode?=false
+TrimmingEligibleMethodsOutputDirectory?= #
+
+#MIBC_PROFILE_PATH=
+
+MONO_ENV_OPTIONS ?=
+
+publish:
+ $(DOTNET) publish \
+ -c $(MONO_CONFIG) \
+ -r $(TARGET_OS)-$(MONO_ARCH) \
+ /p:RunAOTCompilation=$(AOT) \
+ /p:MonoEnableLLVM=$(USE_LLVM) \
+ /p:StripILCode=$(StripILCode) \
+ /p:TrimmingEligibleMethodsOutputDirectory=$(TrimmingEligibleMethodsOutputDirectory) \
+ '/p:MibcProfilePath="$(MIBC_PROFILE_PATH)"' \
+ /bl
+
+run: publish
+ DOTNET_DebugWriteToStdErr=1 \
+ MONO_ENV_OPTIONS="$(MONO_ENV_OPTIONS)" \
+ $(TOP)artifacts/bin/HelloWorld_2/$(MONO_ARCH)/$(MONO_CONFIG)/$(TARGET_OS)-$(MONO_ARCH)/publish/HelloWorld_2
+
+clean:
+ rm -rf $(TOP)artifacts/bin/HelloWorld_2/
diff --git a/src/mono/sample/HelloWorld_2/Program.cs b/src/mono/sample/HelloWorld_2/Program.cs
new file mode 100644
index 00000000000000..c083eba935b9e2
--- /dev/null
+++ b/src/mono/sample/HelloWorld_2/Program.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace HelloWorld_2
+{
+ internal class Program
+ {
+ private static void Main(string[] args)
+ {
+ Console.WriteLine($"Hello World 2");
+ }
+ }
+}