summaryrefslogtreecommitdiff
path: root/src/zap/svcworker.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/zap/svcworker.cpp
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/zap/svcworker.cpp')
-rw-r--r--src/zap/svcworker.cpp1057
1 files changed, 1057 insertions, 0 deletions
diff --git a/src/zap/svcworker.cpp b/src/zap/svcworker.cpp
new file mode 100644
index 0000000000..127c491e84
--- /dev/null
+++ b/src/zap/svcworker.cpp
@@ -0,0 +1,1057 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+
+/**********************************************************************
+svcworker.cpp -- logic for the runtime implementation of the native
+image service.
+
+Overview: the runtime implementation is accessed via a local COM
+server implemented in ngen.exe. That server is simply a stub that
+loads the most recent runtime and calls into the actual implementation
+in this file. There are three entrypoints in mscorwks.dll that
+are called by the local service in ngen.exe:
+
+NGenWorkerRegisterServer -- called to register ngen.exe as the current
+ COM server for CLSID_CorSvcWorker
+NGenWorkerUnregisterServer -- unregister ngen.exe as the current COM
+ server for CLSID_CorSvcWorker
+NGenWorkerEmbedding() -- called when COM invoked the COM server with
+ the "-Embedding" flag. Implements the logic for registering the class
+ factory for CLSID_CorSvcWorker and controlling the lifetime of the
+ COM server.
+**********************************************************************/
+
+#include "common.h"
+
+#ifdef FEATURE_FUSION
+#include "binderngen.h"
+#endif
+
+#ifdef FEATURE_APPX
+#include "AppXUtil.h"
+#endif
+
+ILocalServerLifetime *g_pLocalServerLifetime = NULL;
+
+SvcLogger::SvcLogger()
+ : pss(NULL),
+ pCorSvcLogger(NULL)
+{
+}
+
+inline void SvcLogger::CheckInit()
+{
+ if(pss == NULL)
+ {
+ StackSString* psstemp = new StackSString();
+ StackSString* pssOrig = InterlockedCompareExchangeT(&pss, psstemp, NULL);
+ if(pssOrig)
+ delete psstemp;
+ }
+}
+
+SvcLogger::~SvcLogger()
+{
+ if (pCorSvcLogger)
+ {
+// pCorSvcLogger->Release();
+ pCorSvcLogger = NULL;
+ }
+ if (pss)
+ delete pss;
+}
+
+void SvcLogger::ReleaseLogger()
+{
+ if (pCorSvcLogger)
+ {
+ pCorSvcLogger->Release();
+ pCorSvcLogger = NULL;
+ }
+}
+
+void SvcLogger::Printf(const CHAR *format, ...)
+{
+ StackSString s;
+
+ va_list args;
+ va_start(args, format);
+ s.VPrintf(format, args);
+ va_end(args);
+
+ if (pCorSvcLogger)
+ {
+ LogHelper(s);
+ }
+ else
+ {
+ wprintf( W("%s"), s.GetUnicode() );
+ }
+}
+
+void SvcLogger::SvcPrintf(const CHAR *format, ...)
+{
+ StackSString s;
+
+ va_list args;
+ va_start(args, format);
+ s.VPrintf(format, args);
+ va_end(args);
+
+ LogHelper(s);
+}
+
+void SvcLogger::Printf(const WCHAR *format, ...)
+{
+ StackSString s;
+
+ va_list args;
+ va_start(args, format);
+ s.VPrintf(format, args);
+ va_end(args);
+
+ if (pCorSvcLogger)
+ {
+ LogHelper(s);
+ }
+ else
+ {
+ wprintf( W("%s"), s.GetUnicode() );
+ }
+}
+
+void SvcLogger::Printf(CorSvcLogLevel logLevel, const WCHAR *format, ...)
+{
+ StackSString s;
+
+ va_list args;
+ va_start(args, format);
+ s.VPrintf(format, args);
+ va_end(args);
+
+ if (pCorSvcLogger)
+ {
+ LogHelper(s, logLevel);
+ }
+ else
+ {
+ wprintf( W("%s"), s.GetUnicode());
+ }
+}
+
+void SvcLogger::SvcPrintf(const WCHAR *format, ...)
+{
+ StackSString s;
+
+ va_list args;
+ va_start(args, format);
+ s.VPrintf(format, args);
+ va_end(args);
+
+ LogHelper(s);
+}
+
+void SvcLogger::Log(const WCHAR *message, CorSvcLogLevel logLevel)
+{
+ LogHelper(StackSString(message), logLevel);
+}
+
+void SvcLogger::LogHelper(SString s, CorSvcLogLevel logLevel)
+{
+ CheckInit();
+ pss->Append(s);
+
+ // Does s contain a newline?
+ SString::Iterator i = pss->Begin();
+ if (pss->FindASCII(i, "\n"))
+ {
+ if (pCorSvcLogger)
+ {
+ BSTRHolder bstrHolder(::SysAllocString(pss->GetUnicode()));
+ // Can't use the IfFailThrow macro here because in checked
+ // builds that macros will try to log an error message
+ // that will recursively return to this method.
+ HRESULT hr = pCorSvcLogger->Log(logLevel, bstrHolder);
+ if (FAILED(hr))
+ ThrowHR(hr);
+ }
+ pss->Clear();
+ }
+}
+
+void SvcLogger::SetSvcLogger(ICorSvcLogger *pCorSvcLoggerArg)
+{
+ ReleaseLogger();
+ this->pCorSvcLogger = pCorSvcLoggerArg;
+ if (pCorSvcLoggerArg)
+ {
+ pCorSvcLogger->AddRef();
+ }
+}
+
+BOOL SvcLogger::HasSvcLogger()
+{
+ return (this->pCorSvcLogger != NULL);
+}
+
+ICorSvcLogger* SvcLogger::GetSvcLogger()
+{
+ return pCorSvcLogger;
+}
+
+#ifndef FEATURE_CORECLR
+
+void InitNGenOptions(NGenOptions *ngo,
+ NGenPrivateAttributes ngenPrivateAttributes,
+ OptimizationScenario optScenario = ScenarioDefault,
+ LPCWSTR lpszRepositoryDir = NULL, RepositoryFlags repositoryFlags = RepositoryDefault)
+{
+ ULONG_PTR pScenario = (ULONG_PTR) optScenario;
+
+ ngo->dwSize = sizeof(NGenOptions);
+
+ // V1
+ //
+ ngo->fDebug = (pScenario & ScenarioDebug) ? true : false;
+ ngo->fDebugOpt = false;
+ ngo->fProf = (pScenario & ScenarioProfile) ? true : false;
+ ngo->fSilent = false;
+ ngo->lpszExecutableFileName = NULL;
+
+ // V2 (Whidbey)
+ //
+ ngo->fInstrument = (pScenario & ScenarioTuningDataCollection) ? true : false;
+ ngo->fWholeProgram = false;
+ ngo->fProfInfo = (pScenario & ScenarioProfileInfo) ? true : false;
+
+ ngo->lpszRepositoryDir = lpszRepositoryDir;
+ ngo->repositoryFlags = repositoryFlags;
+
+ ngo->dtRequested = DT_NIL;
+ ngo->lpszDebugDir = NULL;
+
+ ngo->fNoInstall = false;
+ ngo->fEmitFixups = false;
+ ngo->fFatHeaders = false;
+ ngo->fVerbose = false;
+
+ // This should be a value from the StatOptions enumeration
+ ngo->uStats = ngenPrivateAttributes.ZapStats;
+ ngo->dtRequested = (ngenPrivateAttributes.Flags & DbgTypePdb) ? DT_PDB : DT_NIL;
+ ngo->lpszDebugDir = ngenPrivateAttributes.DbgDir;
+
+
+ // V4
+ //
+ ngo->fNgenLastRetry = (pScenario & ScenarioNgenLastRetry) ? true : false;
+
+ // V4.5
+ ngo->fAutoNGen = (pScenario & ScenarioAutoNGen) ? true : false;
+
+ // Blue
+ ngo->fRepositoryOnly = (pScenario & ScenarioRepositoryOnly) ? true : false;
+}
+
+#endif // !FEATURE_CORECLR
+
+namespace
+{
+ SvcLogger *g_SvcLogger = NULL;
+}
+
+// As NGen is currently single-threaded, this function is intentionally not thread safe.
+// If necessary, change it into an interlocked function.
+SvcLogger *GetSvcLogger()
+{
+ if (g_SvcLogger == NULL)
+ {
+ g_SvcLogger = new SvcLogger();
+ }
+ return g_SvcLogger;
+}
+
+BOOL HasSvcLogger()
+{
+ if (g_SvcLogger != NULL)
+ {
+ return g_SvcLogger->HasSvcLogger();
+ }
+ return FALSE;
+}
+
+#ifdef CROSSGEN_COMPILE
+void SetSvcLogger(ICorSvcLogger *pCorSvcLogger)
+{
+ GetSvcLogger()->SetSvcLogger(pCorSvcLogger);
+}
+#endif
+
+#ifndef FEATURE_CORECLR
+
+//*****************************************************************************
+// ICorSvcDependencies is used to enumerate the dependencies of an
+// IL image. It is used by the native image service.
+//*****************************************************************************[
+class CCorSvcDependencies : public ICorSvcDependencies
+{
+public:
+ CCorSvcDependencies()
+ {
+ _cRef = 0;
+ zapper = NULL;
+
+ g_pLocalServerLifetime->AddRefServerProcess();
+ }
+
+ ~CCorSvcDependencies()
+ {
+ if (zapper != NULL)
+ {
+ delete zapper;
+ }
+
+ g_pLocalServerLifetime->ReleaseServerProcess();
+ }
+
+ void Initialize(BSTR pApplicationName, OptimizationScenario scenario)
+ {
+ NGenOptions opt = {0};
+ NGenPrivateAttributesClass ngenPrivateAttributesClass;
+ InitNGenOptions(&opt, ngenPrivateAttributesClass, scenario);
+ opt.lpszExecutableFileName = pApplicationName;
+ zapper = Zapper::NewZapper(&opt, true);
+ zapper->CreateDependenciesLookupDomain();
+ }
+
+ STDMETHOD (GetAssemblyDependencies)(
+ BSTR pAssemblyName,
+ SAFEARRAY **pDependencies,
+ DWORD *assemblyNGenSetting,
+ BSTR *pNativeImageIdentity,
+ BSTR *pAssemblyDisplayName,
+ SAFEARRAY **pDependencyLoadSetting,
+ SAFEARRAY **pDependencyNGenSetting
+ )
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ _ASSERTE(zapper != NULL);
+ _ASSERTE(pNativeImageIdentity);
+
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ GUID nativeImageSign = INVALID_NGEN_SIGNATURE;
+ zapper->ComputeDependencies(pAssemblyName, &nativeImageSign);
+
+ BSTRHolder displayNameHolder(::SysAllocString(zapper->m_assemblyDependencies.GetDisplayName()));
+
+ *pDependencies = zapper->m_assemblyDependencies.GetSAFEARRAY();
+ *assemblyNGenSetting = zapper->m_assemblyDependencies.GetNGenHint();
+ *pDependencyLoadSetting = zapper->m_assemblyDependencies.GetLoadHintSAFEARRAY();
+ *pDependencyNGenSetting = zapper->m_assemblyDependencies.GetNGenHintSAFEARRAY();
+
+ if (nativeImageSign != INVALID_NGEN_SIGNATURE)
+ {
+ WCHAR szGuid[64];
+ if (GuidToLPWSTR(nativeImageSign, szGuid, sizeof(szGuid) / sizeof(WCHAR)) == 0)
+ {
+ ThrowHR(E_UNEXPECTED);
+ }
+ *pNativeImageIdentity = ::SysAllocString(szGuid);
+ }
+
+ *pAssemblyDisplayName = displayNameHolder.Extract();
+ }
+ EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement (&_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ ULONG lRet = InterlockedDecrement (&_cRef);
+ if (!lRet)
+ delete this;
+ return lRet;
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ if (!ppv)
+ return E_POINTER;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_ICorSvcDependencies))
+ {
+ *ppv = static_cast<ICorSvcDependencies*> (this);
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+private:
+ LONG _cRef;
+ Zapper *zapper;
+};
+
+//*****************************************************************************
+// CCorSvcCreatePdbWorker is used to load the CLR, initialize an appdomain,
+// load the given assembly and create a PDB for it.
+//*****************************************************************************
+class CCorSvcCreatePdbWorker {
+
+public:
+
+ CCorSvcCreatePdbWorker()
+ : m_pZapper(NULL)
+ {
+ }
+
+ ~CCorSvcCreatePdbWorker()
+ {
+ if (m_pZapper)
+ delete m_pZapper;
+ }
+
+ void Initialize(BSTR pAppBaseOrConfig, OptimizationScenario scenario)
+ {
+ _ASSERTE(m_pZapper == NULL);
+
+ NGenOptions options = {0};
+ NGenPrivateAttributesClass privateAttributesClass;
+
+ InitNGenOptions(&options, privateAttributesClass, scenario);
+ options.lpszExecutableFileName = pAppBaseOrConfig;
+ m_pZapper = Zapper::NewZapper(&options, true);
+ m_pZapper->CreateDependenciesLookupDomain();
+ }
+
+
+ HRESULT CreatePdb(BSTR pAssemblyName, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath)
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+ _ASSERTE(m_pZapper);
+
+ HRESULT hr = S_OK;
+ EX_TRY {
+
+ m_pZapper->CreatePdb(pAssemblyName, pNativeImagePath, pPdbPath, pdbLines, pManagedPdbSearchPath);
+
+ } EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+ }
+
+private:
+
+ Zapper *m_pZapper;
+
+};
+
+#ifdef _DEBUG
+ inline void DoFreeEnvironmentStrings(LPTCH lpszEnvironmentBlock)
+ {
+ WszFreeEnvironmentStrings(lpszEnvironmentBlock);
+ }
+ typedef Wrapper<LPTCH, DoNothing, DoFreeEnvironmentStrings> EnvHolder;
+#endif //_DEBUG
+
+//*****************************************************************************
+// ICorSvcWorker contains methods for generating native images and enumerating
+// their dependencies.
+//*****************************************************************************[
+class CCorSvcWorker :
+ public ICorSvcWorker3,
+ public ICorSvcRepository,
+ public ICorSvcSetPrivateAttributes,
+#ifdef FEATURE_APPX
+ public ICorSvcAppX,
+#endif
+ public ICorSvcPooledWorker
+{
+public:
+ CCorSvcWorker() :
+ _cRef(0),
+ repositoryDir(NULL),
+ repositoryFlags(RepositoryDefault),
+ ngenPrivateAttributesClass()
+
+#ifdef FEATURE_FUSION
+ ,
+ pAssemblyCache(NULL)
+#endif
+ {
+ g_pLocalServerLifetime->AddRefServerProcess();
+ }
+
+ ~CCorSvcWorker()
+ {
+#ifdef FEATURE_FUSION
+ if (pAssemblyCache != NULL)
+ {
+ pAssemblyCache->Release();
+ pAssemblyCache = NULL;
+ }
+#endif
+
+ GetSvcLogger()->ReleaseLogger();
+
+ g_pLocalServerLifetime->ReleaseServerProcess();
+ }
+
+ STDMETHOD (SetPriority)(
+ /*[in]*/ SvcWorkerPriority priority
+ )
+ {
+ HRESULT hr = E_FAIL;
+
+ // Set ourselves to the priority
+ if (::SetPriorityClass(GetCurrentProcess(), priority.dwPriorityClass) == FALSE)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto DONE;
+ }
+
+ hr = S_OK;
+ DONE:
+ return hr;
+ }
+
+#ifdef _DEBUG
+ void Debug_CheckPPLProcessStatus(
+ LPCWSTR wszAssemblyName)
+ {
+ size_t cchAssemblyName = wcslen(wszAssemblyName);
+
+ // Check if we are in PPL (Protected Process Lightweight) by checking existence of LOCALAPPDATA env. var. (it is not present in PPL)
+ BOOL fIsProcessPPL = TRUE;
+ EnvHolder pEnvironmentStrings(WszGetEnvironmentStrings());
+ for (LPTCH pEnv = pEnvironmentStrings; ((pEnv != NULL) && (*pEnv != W('\0'))); pEnv += wcslen(pEnv) + 1)
+ {
+ static const WCHAR const_wszLocalAppData[] = W("LOCALAPPDATA=");
+ static const size_t const_cchLocalAppData = _countof(const_wszLocalAppData) - 1;
+ if (_wcsnicmp(pEnv, const_wszLocalAppData, const_cchLocalAppData) == 0)
+ { // LOCALAPPDATA is never set in PPL process
+ fIsProcessPPL = FALSE;
+ break;
+ }
+ }
+
+ // Semicolon-separated list of names that should assert a failure
+ NewArrayHolder<WCHAR> wszAssertList = NULL;
+ if (fIsProcessPPL)
+ { // If we are in PPL, we should assert for assemblies that are fobidden to be ngen'd in PPL
+ CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NGenProtectedProcess_ForbiddenList, &wszAssertList);
+ }
+ else
+ { // If we are not in PPL, we should assert for assemblies that require to be ngen'd in PPL
+ CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NGenProtectedProcess_RequiredList, &wszAssertList);
+ }
+
+ if ((wszAssertList != NULL) && (*wszAssertList != W('\0')))
+ {
+ LPCWSTR pAssertListName = wszAssertList;
+ for (;;)
+ {
+ LPCWSTR pAssertListNameEnd = wcschr(pAssertListName, W(';'));
+ size_t cchAssertListName;
+ if (pAssertListNameEnd == NULL)
+ { // There is not another semicolon
+ cchAssertListName = wcslen(pAssertListName);
+ }
+ else
+ {
+ cchAssertListName = pAssertListNameEnd - pAssertListName;
+ }
+
+ if ((cchAssertListName > 0) && (cchAssertListName <= cchAssemblyName))
+ {
+ // Check prefix or suffix of assembly name (which is either file name or assembly identity name)
+ if ((_wcsnicmp(wszAssemblyName, pAssertListName, cchAssertListName) == 0) ||
+ (_wcsnicmp(wszAssemblyName + cchAssemblyName - cchAssertListName, pAssertListName, cchAssertListName) == 0))
+ {
+ if (fIsProcessPPL)
+ {
+ _ASSERTE_MSG(FALSE, "Assembly that is in NGenProtectedProcess_ForbiddenList is ngen'd in PPL process!");
+ }
+ else
+ {
+ _ASSERTE_MSG(FALSE, "Assembly that is in NGenProtectedProcess_RequiredList is ngen'd in normal (non-PPL) process!");
+ }
+ }
+ }
+
+ if (pAssertListNameEnd == NULL)
+ { // There are no more names in the semicolon-separated list
+ break;
+ }
+
+ // Move to next item in the semicolon-separated list (skip also the semicolon)
+ pAssertListName = pAssertListNameEnd + 1;
+ }
+ }
+ } // Debug_CheckPPLProcessStatus
+#endif //_DEBUG
+
+ STDMETHOD (OptimizeAssembly)(
+ BSTR pAssemblyName,
+ BSTR pApplicationName,
+ OptimizationScenario scenario,
+ SAFEARRAY *loadAlwaysList,
+ SAFEARRAY *loadSometimesList,
+ SAFEARRAY *loadNeverList,
+ BSTR *pNativeImageIdentity
+ )
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ INDEBUG(Debug_CheckPPLProcessStatus(pAssemblyName);)
+
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+#if defined(_DEBUG) || defined(ALLOW_LOCAL_WORKER)
+ // Make sure optimize is called only once per process
+ static int OptimizeCount = 0;
+#ifdef ALLOW_LOCAL_WORKER
+ if (OptimizeCount != 0)
+ {
+ GetSvcLogger()->Printf(W("You cannot call OptimizeAssembly twice. If you are using COMPLUS_NgenLocalWorker, make sure you are only optimizing one assembly.\r\n"));
+ ThrowHR(E_FAIL);
+ }
+#else // _DEBUG
+ _ASSERTE(OptimizeCount == 0);
+#endif
+ OptimizeCount++;
+#endif
+
+ NGenOptions opt = {0};
+ InitNGenOptions(&opt, ngenPrivateAttributesClass, scenario, repositoryDir, repositoryFlags);
+ opt.lpszExecutableFileName = pApplicationName;
+
+ GUID nativeImageSign;
+ bool hasProfileData;
+
+ hr = ZapperCompileWrapper(pAssemblyName, &opt, &nativeImageSign,
+ loadAlwaysList, loadSometimesList, loadNeverList,
+ true, &hasProfileData);
+#if 0
+ // Unfotunately we can't perform a retry here as the Zapper currently
+ // allocates and initializes some things once CompilationDomain and
+ // thus some of this stuff will leak from the failed complation.
+ //
+ if (FAILED(hr) && hasProfileData && retryNgenFailures)
+ {
+ hr = ZapperCompileWrapper(pAssemblyName, &opt, &nativeImageSign,
+ loadAlwaysList, loadSometimesList, loadNeverList,
+ false, NULL);
+ if (SUCCEEDED(hr))
+ {
+ StackSString msg;
+ msg.Printf(W("The compile failed when the profile data was used and ")
+ W("the compile succeeded when the profile data was ignored."));
+ GetSvcLogger()->Log(msg, LogLevel_Info);
+ }
+ }
+#endif
+ IfFailThrow(hr);
+
+ _ASSERTE(nativeImageSign != INVALID_NGEN_SIGNATURE || opt.fRepositoryOnly);
+
+ _ASSERTE(pNativeImageIdentity);
+ if (nativeImageSign != INVALID_NGEN_SIGNATURE)
+ {
+ WCHAR szGuid[64];
+ if (GuidToLPWSTR(nativeImageSign, szGuid, sizeof(szGuid) / sizeof(WCHAR)) == 0)
+ ThrowHR(E_UNEXPECTED);
+ *pNativeImageIdentity = ::SysAllocString(szGuid);
+ }
+ else
+ {
+ *pNativeImageIdentity = NULL;
+ }
+ }
+ EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+ }
+
+ STDMETHOD (DeleteNativeImage)(
+ BSTR pAssemblyName,
+ BSTR pNativeImage
+ )
+ {
+ // The caller must either specify both parameters, or specify neither.
+ _ASSERTE((pAssemblyName == NULL && pNativeImage == NULL) ||
+ (pAssemblyName != NULL && pNativeImage != NULL));
+
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ NGenOptions opt = {0};
+ InitNGenOptions(&opt, ngenPrivateAttributesClass);
+ NewHolder<Zapper> zapper = Zapper::NewZapper(&opt, true);
+ _ASSERTE(zapper != NULL);
+
+ GUID *pNativeImageMVID = NULL;
+ GUID nativeImageMVID;
+
+ if (pNativeImage)
+ {
+ StackSString nativeImageString(pNativeImage);
+ StackScratchBuffer buffer;
+ LPCSTR pstr = nativeImageString.GetANSI(buffer);
+ IfFailThrow(LPCSTRToGuid((LPCSTR) pstr, &nativeImageMVID));
+ pNativeImageMVID = &nativeImageMVID;
+ }
+
+#ifdef FEATURE_FUSION
+ if (pAssemblyName != NULL && pNativeImageMVID != NULL)
+ {
+ // Deleting a specific native image.
+ zapper->DeleteFusionCacheEntry(pAssemblyName, pNativeImageMVID);
+ }
+ else if (pAssemblyName != NULL || pNativeImageMVID != NULL)
+ {
+ hr = E_UNEXPECTED;
+ }
+ else
+ {
+ // Not deleting a specific native image. Need to enumerate NIC.
+ IfFailThrow(zapper->EnumerateFusionCache(NULL, false, true, NULL));
+ }
+#else //FEATURE_FUSION
+ _ASSERTE(!"NYI");
+#endif //FEATURE_FUSION
+ }
+ EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+ }
+
+ STDMETHOD (DisplayNativeImages)(BSTR pAssemblyName)
+ {
+#ifdef FEATURE_FUSION
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ NGenOptions opt = {0};
+ InitNGenOptions(&opt, ngenPrivateAttributesClass);
+ NewHolder<Zapper> zapper = Zapper::NewZapper(&opt, true);
+ _ASSERTE(zapper != NULL);
+
+ IfFailThrow(zapper->EnumerateFusionCache(pAssemblyName, true, false, NULL));
+ }
+ EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+#else //FEATURE_FUSION
+ return E_NOTIMPL;
+#endif //FEATURE_FUSION
+ }
+
+ STDMETHOD(GetCorSvcDependencies)(
+ BSTR pApplicationName,
+ OptimizationScenario scenario,
+ ICorSvcDependencies **ppCorSvcDependencies
+ )
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ NewHolder<CCorSvcDependencies> pCorSvcDependencies(new CCorSvcDependencies());
+ pCorSvcDependencies->Initialize(pApplicationName, scenario);
+ IfFailThrow(pCorSvcDependencies->QueryInterface(IID_ICorSvcDependencies, (void **) ppCorSvcDependencies));
+ pCorSvcDependencies.SuppressRelease();
+ }
+ EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+ }
+
+ STDMETHOD(Stop)()
+ {
+ return S_OK;
+ }
+
+ STDMETHOD(CreatePdb)(__in BSTR pAssemblyName,
+ __in BSTR pAppBaseOrConfig,
+ __in OptimizationScenario scenario,
+ __in BSTR pNativeImagePath,
+ __in BSTR pPdbPath)
+ {
+ return CreatePdb2(
+ pAssemblyName,
+ pAppBaseOrConfig,
+ scenario,
+ pNativeImagePath,
+ pPdbPath,
+ FALSE,
+ NULL);
+ }
+
+ STDMETHOD(CreatePdb2)(__in BSTR pAssemblyName,
+ __in BSTR pAppBaseOrConfig,
+ __in OptimizationScenario scenario,
+ __in BSTR pNativeImagePath,
+ __in BSTR pPdbPath,
+ __in BOOL pdbLines,
+ __in BSTR pManagedPdbSearchPath)
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ HRESULT hr = S_OK;
+
+ EX_TRY {
+
+ CCorSvcCreatePdbWorker worker;
+ worker.Initialize(pAppBaseOrConfig, scenario);
+ hr = worker.CreatePdb(pAssemblyName, pNativeImagePath, pPdbPath, pdbLines, pManagedPdbSearchPath);
+
+ } EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+
+ return hr;
+ }
+
+#ifdef FEATURE_APPX
+ STDMETHOD(SetPackage)(__in BSTR pPackageFullName)
+ {
+ return AppX::SetCurrentPackageForNGen(pPackageFullName);
+ }
+
+ STDMETHOD(SetLocalAppDataDirectory)(__in BSTR pLocalAppDataDirectory)
+ {
+ return Clr::Util::SetLocalAppDataDirectory(pLocalAppDataDirectory);
+ }
+#endif
+
+ STDMETHOD (SetRepository)(
+ BSTR pRepositoryDir,
+ RepositoryFlags flags
+ )
+ {
+ _ASSERTE(repositoryFlags == RepositoryDefault);
+ _ASSERTE(repositoryDir == NULL);
+
+ repositoryDir = ::SysAllocString(pRepositoryDir);
+ repositoryFlags = flags;
+
+ return S_OK;
+ }
+
+ STDMETHOD (SetNGenPrivateAttributes)(
+ NGenPrivateAttributes ngenPrivateAttributes
+ )
+ {
+ _ASSERTE(ngenPrivateAttributesClass.Flags == 0);
+ _ASSERTE(ngenPrivateAttributesClass.ZapStats == 0);
+
+ ngenPrivateAttributesClass.Flags = ngenPrivateAttributes.Flags;
+ ngenPrivateAttributesClass.ZapStats = ngenPrivateAttributes.ZapStats;
+
+ if (ngenPrivateAttributes.DbgDir)
+ {
+ _ASSERTE(ngenPrivateAttributesClass.DbgDir == NULL);
+ ngenPrivateAttributesClass.DbgDir = ::SysAllocString(ngenPrivateAttributes.DbgDir);
+ }
+
+ return S_OK;
+ }
+
+ STDMETHOD (CanReuseProcess)(
+ OptimizationScenario scenario,
+ ICorSvcLogger *pCorSvcLogger,
+ BOOL *pCanContinue)
+ {
+ SO_NOT_MAINLINE_FUNCTION;
+
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pCanContinue != NULL);
+ *pCanContinue = FALSE;
+
+ return hr;
+ }
+
+ static HRESULT CreateObject(REFIID riid, void **ppUnk)
+ {
+ HRESULT hr;
+ CCorSvcWorker *pCorSvcWorker = new (nothrow) CCorSvcWorker();
+
+ if (pCorSvcWorker == 0)
+ return (E_OUTOFMEMORY);
+
+ hr = pCorSvcWorker->QueryInterface(riid, ppUnk);
+ if (FAILED(hr))
+ delete pCorSvcWorker;
+ return (hr);
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement (&_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ ULONG lRet = InterlockedDecrement (&_cRef);
+ if (!lRet)
+ delete this;
+ return lRet;
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
+ {
+ if (!ppv)
+ return E_POINTER;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_ICorSvcWorker))
+ {
+ *ppv = static_cast<ICorSvcWorker*> (this);
+ AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID(riid, IID_ICorSvcWorker2))
+ {
+ *ppv = static_cast<ICorSvcWorker2 *>(this);
+ AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID(riid, IID_ICorSvcWorker3))
+ {
+ *ppv = static_cast<ICorSvcWorker3 *>(this);
+ AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID(riid, IID_ICorSvcRepository))
+ {
+ *ppv = static_cast<ICorSvcRepository*> (this);
+ AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID(riid, IID_ICorSvcSetPrivateAttributes))
+ {
+ *ppv = static_cast<ICorSvcSetPrivateAttributes *> (this);
+ AddRef();
+ return S_OK;
+ }
+#ifdef FEATURE_APPX
+ else if (IsEqualIID(riid, IID_ICorSvcAppX))
+ {
+ *ppv = static_cast<ICorSvcAppX *> (this);
+ AddRef();
+ return S_OK;
+ }
+#endif
+ else if (IsEqualIID(riid, IID_ICorSvcPooledWorker))
+ {
+ *ppv = static_cast<ICorSvcPooledWorker *> (this);
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+private:
+ HRESULT ZapperCompileWrapper(BSTR pAssemblyName,
+ NGenOptions * pOpt,
+ GUID * pNativeImageSign,
+ SAFEARRAY * loadAlwaysList,
+ SAFEARRAY * loadSometimesList,
+ SAFEARRAY * loadNeverList,
+ bool useProfileData,
+ bool * pHasProfileData)
+ {
+ NewHolder<Zapper> zapper(Zapper::NewZapper(pOpt, true));
+
+ *pNativeImageSign = INVALID_NGEN_SIGNATURE;
+
+ // Push the load lists to the zapper
+ zapper->SetLoadLists(loadAlwaysList, loadSometimesList, loadNeverList);
+ if (useProfileData == false)
+ {
+ zapper->DontUseProfileData();
+ }
+
+ HRESULT hr = zapper->Compile(pAssemblyName, pNativeImageSign);
+
+ if (pHasProfileData != NULL)
+ {
+ *pHasProfileData = zapper->HasProfileData();
+ }
+
+ if (!FAILED(hr) && (*pNativeImageSign == INVALID_NGEN_SIGNATURE) && !pOpt->fRepositoryOnly)
+ {
+ // Unfortunately we can get a passing HR when an EE exception was
+ // thrown because the zapper EH logic can't get the correct HR
+ // out of the EE exception. This will be fixed, but for now we
+ // should also return E_FAIL in that case.
+
+ hr = E_FAIL;
+ }
+
+ return hr;
+ }
+
+private:
+ LONG _cRef;
+
+ BSTRHolder repositoryDir;
+ RepositoryFlags repositoryFlags;
+
+ NGenPrivateAttributesClass ngenPrivateAttributesClass;
+
+#ifdef FEATURE_FUSION
+ IAssemblyCache *pAssemblyCache;
+#endif // FEATURE_FUSION
+};
+
+STDAPI NGenCreateNGenWorker(ICorSvcWorker **pCorSvcWorker, ILocalServerLifetime *pLocalServerLifetime, ICorSvcLogger *pCorSvcLogger)
+{
+
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ EX_TRY
+ {
+ _ASSERTE(pLocalServerLifetime);
+ //_ASSERTE(g_pLocalServerLifetime == NULL);
+
+ g_pLocalServerLifetime = pLocalServerLifetime;
+
+ GetSvcLogger()->SetSvcLogger(pCorSvcLogger);
+
+ IfFailThrow(CCorSvcWorker::CreateObject(IID_ICorSvcWorker, (void **) pCorSvcWorker));
+ }
+ EX_CATCH_HRESULT_AND_NGEN_CLEAN(hr);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+#endif // !FEATURE_CORECLR