diff options
Diffstat (limited to 'src/dlls/mscoree/unixinterface.cpp')
-rw-r--r-- | src/dlls/mscoree/unixinterface.cpp | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/src/dlls/mscoree/unixinterface.cpp b/src/dlls/mscoree/unixinterface.cpp new file mode 100644 index 0000000000..8d75ff2721 --- /dev/null +++ b/src/dlls/mscoree/unixinterface.cpp @@ -0,0 +1,378 @@ +// 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. + + +//***************************************************************************** +// unixinterface.cpp +// +// Implementation for the interface exposed by libcoreclr.so +// + +//***************************************************************************** + +#include "stdafx.h" +#include <utilcode.h> +#include <corhost.h> +#include <configuration.h> +#ifdef FEATURE_GDBJIT +#include "../../vm/gdbjithelpers.h" +#endif // FEATURE_GDBJIT + +typedef int (STDMETHODCALLTYPE *HostMain)( + const int argc, + const wchar_t** argv + ); + +#define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr)) + +// Holder for const wide strings +typedef NewArrayHolder<const WCHAR> ConstWStringHolder; + +// Holder for array of wide strings +class ConstWStringArrayHolder : public NewArrayHolder<LPCWSTR> +{ + int m_cElements; + +public: + ConstWStringArrayHolder() : + NewArrayHolder<LPCWSTR>(), + m_cElements(0) + { + } + + void Set(LPCWSTR* value, int cElements) + { + NewArrayHolder<LPCWSTR>::operator=(value); + m_cElements = cElements; + } + + ~ConstWStringArrayHolder() + { + for (int i = 0; i < m_cElements; i++) + { + delete [] this->m_value[i]; + } + } +}; + +// Convert 8 bit string to unicode +static LPCWSTR StringToUnicode(LPCSTR str) +{ + int length = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + ASSERTE_ALL_BUILDS(length != 0); + + LPWSTR result = new (nothrow) WCHAR[length]; + ASSERTE_ALL_BUILDS(result != NULL); + + length = MultiByteToWideChar(CP_UTF8, 0, str, -1, result, length); + ASSERTE_ALL_BUILDS(length != 0); + + return result; +} + +// Convert 8 bit string array to unicode string array +static LPCWSTR* StringArrayToUnicode(int argc, LPCSTR* argv) +{ + LPCWSTR* argvW = nullptr; + + if (argc > 0) + { + argvW = new (nothrow) LPCWSTR[argc]; + ASSERTE_ALL_BUILDS(argvW != 0); + + for (int i = 0; i < argc; i++) + { + argvW[i] = StringToUnicode(argv[i]); + } + } + + return argvW; +} + +static void InitializeStartupFlags(STARTUP_FLAGS* startupFlagsRef) +{ + STARTUP_FLAGS startupFlags = static_cast<STARTUP_FLAGS>( + STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | + STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN); + + if (Configuration::GetKnobBooleanValue(W("System.GC.Concurrent"), CLRConfig::UNSUPPORTED_gcConcurrent)) + { + startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_CONCURRENT_GC); + } + if (Configuration::GetKnobBooleanValue(W("System.GC.Server"), CLRConfig::UNSUPPORTED_gcServer)) + { + startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_SERVER_GC); + } + if (Configuration::GetKnobBooleanValue(W("System.GC.RetainVM"), CLRConfig::UNSUPPORTED_GCRetainVM)) + { + startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_HOARD_GC_VM); + } + + *startupFlagsRef = startupFlags; +} + +static void ConvertConfigPropertiesToUnicode( + const char** propertyKeys, + const char** propertyValues, + int propertyCount, + LPCWSTR** propertyKeysWRef, + LPCWSTR** propertyValuesWRef) +{ + LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount]; + ASSERTE_ALL_BUILDS(propertyKeysW != nullptr); + + LPCWSTR* propertyValuesW = new (nothrow) LPCWSTR[propertyCount]; + ASSERTE_ALL_BUILDS(propertyValuesW != nullptr); + + for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex) + { + propertyKeysW[propertyIndex] = StringToUnicode(propertyKeys[propertyIndex]); + propertyValuesW[propertyIndex] = StringToUnicode(propertyValues[propertyIndex]); + } + + *propertyKeysWRef = propertyKeysW; + *propertyValuesWRef = propertyValuesW; +} + +#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) +// Reference to the global holding the path to the JIT +extern "C" LPCWSTR g_CLRJITPath; +#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) + +#ifdef FEATURE_GDBJIT +GetInfoForMethodDelegate getInfoForMethodDelegate = NULL; +extern "C" int coreclr_create_delegate(void*, unsigned int, const char*, const char*, const char*, void**); +#endif //FEATURE_GDBJIT + +// +// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain +// +// Parameters: +// exePath - Absolute path of the executable that invoked the ExecuteAssembly +// appDomainFriendlyName - Friendly name of the app domain that will be created to execute the assembly +// propertyCount - Number of properties (elements of the following two arguments) +// propertyKeys - Keys of properties of the app domain +// propertyValues - Values of properties of the app domain +// hostHandle - Output parameter, handle of the created host +// domainId - Output parameter, id of the created app domain +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +extern "C" +int coreclr_initialize( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId) +{ + HRESULT hr; +#ifdef FEATURE_PAL + DWORD error = PAL_InitializeCoreCLR(exePath); + hr = HRESULT_FROM_WIN32(error); + + // If PAL initialization failed, then we should return right away and avoid + // calling any other APIs because they can end up calling into the PAL layer again. + if (FAILED(hr)) + { + return hr; + } +#endif + + ReleaseHolder<ICLRRuntimeHost2> host; + + hr = CorHost2::CreateObject(IID_ICLRRuntimeHost2, (void**)&host); + IfFailRet(hr); + + ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName); + + LPCWSTR* propertyKeysW; + LPCWSTR* propertyValuesW; + ConvertConfigPropertiesToUnicode( + propertyKeys, + propertyValues, + propertyCount, + &propertyKeysW, + &propertyValuesW); + + // This will take ownership of propertyKeysWTemp and propertyValuesWTemp + Configuration::InitializeConfigurationKnobs(propertyCount, propertyKeysW, propertyValuesW); + +#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) + // Fetch the path to JIT binary, if specified + g_CLRJITPath = Configuration::GetKnobStringValue(W("JIT_PATH")); +#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) + + STARTUP_FLAGS startupFlags; + InitializeStartupFlags(&startupFlags); + + hr = host->SetStartupFlags(startupFlags); + IfFailRet(hr); + + hr = host->Start(); + IfFailRet(hr); + + hr = host->CreateAppDomainWithManager( + appDomainFriendlyNameW, + // Flags: + // APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS + // - By default CoreCLR only allows platform neutral assembly to be run. To allow + // assemblies marked as platform specific, include this flag + // + // APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP + // - Allows sandboxed applications to make P/Invoke calls and use COM interop + // + // APPDOMAIN_SECURITY_SANDBOXED + // - Enables sandboxing. If not set, the app is considered full trust + // + // APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION + // - Prevents the application from being torn down if a managed exception is unhandled + // + APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS | + APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP | + APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT, + NULL, // Name of the assembly that contains the AppDomainManager implementation + NULL, // The AppDomainManager implementation type name + propertyCount, + propertyKeysW, + propertyValuesW, + (DWORD *)domainId); + + if (SUCCEEDED(hr)) + { + host.SuppressRelease(); + *hostHandle = host; +#ifdef FEATURE_GDBJIT + + hr = coreclr_create_delegate(*hostHandle, + *domainId, + "SOS.NETCore", + "SOS.SymbolReader", + "GetInfoForMethod", + (void**)&getInfoForMethodDelegate); + + if (!SUCCEEDED(hr)) + { + fprintf(stderr, + "Can't create delegate for 'System.Diagnostics.Debug.SymbolReader.SymbolReader.GetInfoForMethod' " + "method - status: 0x%08x\n", hr); + } + hr = S_OK; // We don't need to fail if we can't create delegate +#endif + } + return hr; +} + +// +// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +extern "C" +int coreclr_shutdown( + void* hostHandle, + unsigned int domainId) +{ + ReleaseHolder<ICLRRuntimeHost2> host(reinterpret_cast<ICLRRuntimeHost2*>(hostHandle)); + + HRESULT hr = host->UnloadAppDomain(domainId, true); // Wait until done + IfFailRet(hr); + + hr = host->Stop(); + +#ifdef FEATURE_PAL + PAL_Shutdown(); +#endif + + return hr; +} + +// +// Create a native callable delegate for a managed method. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// entryPointAssemblyName - Name of the assembly which holds the custom entry point +// entryPointTypeName - Name of the type which holds the custom entry point +// entryPointMethodName - Name of the method which is the custom entry point +// delegate - Output parameter, the function stores a pointer to the delegate at the specified address +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +extern "C" +int coreclr_create_delegate( + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate) +{ + ICLRRuntimeHost2* host = reinterpret_cast<ICLRRuntimeHost2*>(hostHandle); + + ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName); + ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName); + ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName); + + HRESULT hr = host->CreateDelegate( + domainId, + entryPointAssemblyNameW, + entryPointTypeNameW, + entryPointMethodNameW, + (INT_PTR*)delegate); + + return hr; +} + +// +// Execute a managed assembly with given arguments +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// argc - Number of arguments passed to the executed assembly +// argv - Array of arguments passed to the executed assembly +// managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint). +// exitCode - Exit code returned by the executed assembly +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +extern "C" +int coreclr_execute_assembly( + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode) +{ + if (exitCode == NULL) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + } + *exitCode = -1; + + ICLRRuntimeHost2* host = reinterpret_cast<ICLRRuntimeHost2*>(hostHandle); + + ConstWStringArrayHolder argvW; + argvW.Set(StringArrayToUnicode(argc, argv), argc); + + ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath); + + HRESULT hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, (DWORD *)exitCode); + IfFailRet(hr); + + return hr; +} |