cf9bbc5c72825acf8bb9473c2673afa0a9100642
[platform/upstream/coreclr.git] / src / dlls / mscoree / unixinterface.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5
6 //*****************************************************************************
7 // unixinterface.cpp
8 //
9 // Implementation for the interface exposed by libcoreclr.so
10 //
11
12 //*****************************************************************************
13
14 #include "stdafx.h"
15 #include <utilcode.h>
16 #include <corhost.h>
17 #include <configuration.h>
18 #ifdef FEATURE_GDBJIT
19 #include "../../vm/gdbjithelpers.h"
20 #endif // FEATURE_GDBJIT
21
22 typedef int (STDMETHODCALLTYPE *HostMain)(
23     const int argc,
24     const wchar_t** argv
25     );
26
27 #define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr))
28
29 // Holder for const wide strings
30 typedef NewArrayHolder<const WCHAR> ConstWStringHolder;
31
32 // Holder for array of wide strings
33 class ConstWStringArrayHolder : public NewArrayHolder<LPCWSTR>
34 {
35     int m_cElements;
36
37 public:
38     ConstWStringArrayHolder() :
39         NewArrayHolder<LPCWSTR>(),
40         m_cElements(0)
41     {
42     }
43
44     void Set(LPCWSTR* value, int cElements)   
45     {                                             
46         NewArrayHolder<LPCWSTR>::operator=(value);                  
47         m_cElements = cElements;
48     }                                             
49
50     ~ConstWStringArrayHolder()
51     {
52         for (int i = 0; i < m_cElements; i++)
53         {
54             delete [] this->m_value[i];
55         }
56     }
57 };
58
59 // Convert 8 bit string to unicode
60 static LPCWSTR StringToUnicode(LPCSTR str)
61 {
62     int length = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
63     ASSERTE_ALL_BUILDS(length != 0);
64
65     LPWSTR result = new (nothrow) WCHAR[length];
66     ASSERTE_ALL_BUILDS(result != NULL);
67     
68     length = MultiByteToWideChar(CP_UTF8, 0, str, -1, result, length);
69     ASSERTE_ALL_BUILDS(length != 0);
70
71     return result;
72 }
73
74 // Convert 8 bit string array to unicode string array
75 static LPCWSTR* StringArrayToUnicode(int argc, LPCSTR* argv)
76 {
77     LPCWSTR* argvW = nullptr;
78     
79     if (argc > 0)
80     {
81         argvW = new (nothrow) LPCWSTR[argc];
82         ASSERTE_ALL_BUILDS(argvW != 0);
83         
84         for (int i = 0; i < argc; i++)
85         {
86             argvW[i] = StringToUnicode(argv[i]);
87         }
88     }
89
90     return argvW;
91 }
92
93 static void InitializeStartupFlags(STARTUP_FLAGS* startupFlagsRef)
94 {
95     STARTUP_FLAGS startupFlags = static_cast<STARTUP_FLAGS>(
96             STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN |
97             STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN);
98
99     if (Configuration::GetKnobBooleanValue(W("System.GC.Concurrent"), CLRConfig::UNSUPPORTED_gcConcurrent))
100     {
101         startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_CONCURRENT_GC);
102     }
103     if (Configuration::GetKnobBooleanValue(W("System.GC.Server"), CLRConfig::UNSUPPORTED_gcServer))
104     {
105         startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_SERVER_GC);
106     }
107     if (Configuration::GetKnobBooleanValue(W("System.GC.RetainVM"), CLRConfig::UNSUPPORTED_GCRetainVM))
108     {
109         startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_HOARD_GC_VM);
110     }
111
112     *startupFlagsRef = startupFlags;
113 }
114
115 static void ConvertConfigPropertiesToUnicode(
116     const char** propertyKeys,
117     const char** propertyValues,
118     int propertyCount,
119     LPCWSTR** propertyKeysWRef,
120     LPCWSTR** propertyValuesWRef)
121 {
122     LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount];
123     ASSERTE_ALL_BUILDS(propertyKeysW != nullptr);
124
125     LPCWSTR* propertyValuesW = new (nothrow) LPCWSTR[propertyCount];
126     ASSERTE_ALL_BUILDS(propertyValuesW != nullptr);
127
128     for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
129     {
130         propertyKeysW[propertyIndex] = StringToUnicode(propertyKeys[propertyIndex]);
131         propertyValuesW[propertyIndex] = StringToUnicode(propertyValues[propertyIndex]);
132     }
133
134     *propertyKeysWRef = propertyKeysW;
135     *propertyValuesWRef = propertyValuesW;
136 }
137
138 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
139 // Reference to the global holding the path to the JIT
140 extern "C" LPCWSTR g_CLRJITPath;
141 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
142
143 #ifdef FEATURE_GDBJIT
144 GetInfoForMethodDelegate getInfoForMethodDelegate = NULL;
145 extern "C" int coreclr_create_delegate(void*, unsigned int, const char*, const char*, const char*, void**);
146 #endif //FEATURE_GDBJIT
147
148 //
149 // Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
150 //
151 // Parameters:
152 //  exePath                 - Absolute path of the executable that invoked the ExecuteAssembly
153 //  appDomainFriendlyName   - Friendly name of the app domain that will be created to execute the assembly
154 //  propertyCount           - Number of properties (elements of the following two arguments)
155 //  propertyKeys            - Keys of properties of the app domain
156 //  propertyValues          - Values of properties of the app domain
157 //  hostHandle              - Output parameter, handle of the created host
158 //  domainId                - Output parameter, id of the created app domain 
159 //
160 // Returns:
161 //  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
162 //
163 extern "C"
164 int coreclr_initialize(
165             const char* exePath,
166             const char* appDomainFriendlyName,
167             int propertyCount,
168             const char** propertyKeys,
169             const char** propertyValues,
170             void** hostHandle,
171             unsigned int* domainId)
172 {
173     HRESULT hr;
174 #ifdef FEATURE_PAL
175     DWORD error = PAL_InitializeCoreCLR(exePath);
176     hr = HRESULT_FROM_WIN32(error);
177
178     // If PAL initialization failed, then we should return right away and avoid
179     // calling any other APIs because they can end up calling into the PAL layer again.
180     if (FAILED(hr))
181     {
182         return hr;
183     }
184 #endif
185
186     ReleaseHolder<ICLRRuntimeHost4> host;
187
188     hr = CorHost2::CreateObject(IID_ICLRRuntimeHost4, (void**)&host);
189     IfFailRet(hr);
190
191     ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName);
192
193     LPCWSTR* propertyKeysW;
194     LPCWSTR* propertyValuesW;
195     ConvertConfigPropertiesToUnicode(
196         propertyKeys,
197         propertyValues,
198         propertyCount,
199         &propertyKeysW,
200         &propertyValuesW);
201
202     // This will take ownership of propertyKeysWTemp and propertyValuesWTemp
203     Configuration::InitializeConfigurationKnobs(propertyCount, propertyKeysW, propertyValuesW);
204
205 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
206     // Fetch the path to JIT binary, if specified
207     g_CLRJITPath = Configuration::GetKnobStringValue(W("JIT_PATH"));
208 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
209
210     STARTUP_FLAGS startupFlags;
211     InitializeStartupFlags(&startupFlags);
212
213     hr = host->SetStartupFlags(startupFlags);
214     IfFailRet(hr);
215
216     hr = host->Start();
217     IfFailRet(hr);
218
219     hr = host->CreateAppDomainWithManager(
220         appDomainFriendlyNameW,
221         // Flags:
222         // APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS
223         // - By default CoreCLR only allows platform neutral assembly to be run. To allow
224         //   assemblies marked as platform specific, include this flag
225         //
226         // APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP
227         // - Allows sandboxed applications to make P/Invoke calls and use COM interop
228         //
229         // APPDOMAIN_SECURITY_SANDBOXED
230         // - Enables sandboxing. If not set, the app is considered full trust
231         //
232         // APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION
233         // - Prevents the application from being torn down if a managed exception is unhandled
234         //
235         APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |
236         APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |
237         APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT,
238         NULL,                    // Name of the assembly that contains the AppDomainManager implementation
239         NULL,                    // The AppDomainManager implementation type name
240         propertyCount,
241         propertyKeysW,
242         propertyValuesW,
243         (DWORD *)domainId);
244
245     if (SUCCEEDED(hr))
246     {
247         host.SuppressRelease();
248         *hostHandle = host;
249 #ifdef FEATURE_GDBJIT
250         HRESULT createDelegateResult;
251         createDelegateResult = coreclr_create_delegate(*hostHandle,
252                                                        *domainId,
253                                                        "SOS.NETCore",
254                                                        "SOS.SymbolReader",
255                                                        "GetInfoForMethod",
256                                                        (void**)&getInfoForMethodDelegate);
257
258 #if defined(_DEBUG)
259         if (!SUCCEEDED(createDelegateResult))
260         {
261             fprintf(stderr,
262                     "Can't create delegate for 'SOS.SymbolReader.GetInfoForMethod' "
263                     "method - status: 0x%08x\n", createDelegateResult);
264         }
265 #endif // _DEBUG
266
267 #endif
268     }
269     return hr;
270 }
271
272 //
273 // Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
274 //
275 // Parameters:
276 //  hostHandle              - Handle of the host
277 //  domainId                - Id of the domain 
278 //
279 // Returns:
280 //  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
281 //
282 extern "C"
283 int coreclr_shutdown(
284             void* hostHandle,
285             unsigned int domainId)
286 {
287     ReleaseHolder<ICLRRuntimeHost4> host(reinterpret_cast<ICLRRuntimeHost4*>(hostHandle));
288
289     HRESULT hr = host->UnloadAppDomain(domainId, true); // Wait until done
290     IfFailRet(hr);
291
292     hr = host->Stop();
293
294 #ifdef FEATURE_PAL
295     PAL_Shutdown();
296 #endif
297
298     return hr;
299 }
300
301 //
302 // Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
303 //
304 // Parameters:
305 //  hostHandle              - Handle of the host
306 //  domainId                - Id of the domain
307 //  latchedExitCode         - Latched exit code after domain unloaded
308 //
309 // Returns:
310 //  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
311 //
312 extern "C"
313 int coreclr_shutdown_2(
314             void* hostHandle,
315             unsigned int domainId,
316             int* latchedExitCode)
317 {
318     ReleaseHolder<ICLRRuntimeHost4> host(reinterpret_cast<ICLRRuntimeHost4*>(hostHandle));
319
320     HRESULT hr = host->UnloadAppDomain2(domainId, true, latchedExitCode); // Wait until done
321     IfFailRet(hr);
322
323     hr = host->Stop();
324
325 #ifdef FEATURE_PAL
326     PAL_Shutdown();
327 #endif
328
329     return hr;
330 }
331
332 //
333 // Create a native callable delegate for a managed method.
334 //
335 // Parameters:
336 //  hostHandle              - Handle of the host
337 //  domainId                - Id of the domain 
338 //  entryPointAssemblyName  - Name of the assembly which holds the custom entry point
339 //  entryPointTypeName      - Name of the type which holds the custom entry point
340 //  entryPointMethodName    - Name of the method which is the custom entry point
341 //  delegate                - Output parameter, the function stores a pointer to the delegate at the specified address
342 //
343 // Returns:
344 //  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
345 //
346 extern "C"
347 int coreclr_create_delegate(
348             void* hostHandle,
349             unsigned int domainId,
350             const char* entryPointAssemblyName,
351             const char* entryPointTypeName,
352             const char* entryPointMethodName,
353             void** delegate)
354 {
355     ICLRRuntimeHost4* host = reinterpret_cast<ICLRRuntimeHost4*>(hostHandle);
356
357     ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName);
358     ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName);
359     ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName);
360
361     HRESULT hr = host->CreateDelegate(
362                             domainId,
363                             entryPointAssemblyNameW,
364                             entryPointTypeNameW,
365                             entryPointMethodNameW,
366                             (INT_PTR*)delegate);
367     
368     return hr;
369 }
370
371 //
372 // Execute a managed assembly with given arguments
373 //
374 // Parameters:
375 //  hostHandle              - Handle of the host
376 //  domainId                - Id of the domain 
377 //  argc                    - Number of arguments passed to the executed assembly
378 //  argv                    - Array of arguments passed to the executed assembly
379 //  managedAssemblyPath     - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
380 //  exitCode                - Exit code returned by the executed assembly
381 //
382 // Returns:
383 //  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
384 //
385 extern "C"
386 int coreclr_execute_assembly(
387             void* hostHandle,
388             unsigned int domainId,
389             int argc,
390             const char** argv,
391             const char* managedAssemblyPath,
392             unsigned int* exitCode)
393 {
394     if (exitCode == NULL)
395     {
396         return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
397     }
398     *exitCode = -1;
399
400     ICLRRuntimeHost4* host = reinterpret_cast<ICLRRuntimeHost4*>(hostHandle);
401
402     ConstWStringArrayHolder argvW;
403     argvW.Set(StringArrayToUnicode(argc, argv), argc);
404     
405     ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath);
406
407     HRESULT hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, (DWORD *)exitCode);
408     IfFailRet(hr);
409
410     return hr;
411 }