SuperPMI replay: fix enviroment variables initialization. (#13596)
authorSergey Andreenko <seandree@microsoft.com>
Tue, 29 Aug 2017 01:14:50 +0000 (18:14 -0700)
committerGitHub <noreply@github.com>
Tue, 29 Aug 2017 01:14:50 +0000 (18:14 -0700)
SuperPMI replay: fix enviroment variables initialization.

If we have mch with mc files with different ENV_variables, we ran them
with the set for the first mc.

src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
src/ToolBox/superpmi/superpmi-shared/methodcontext.h
src/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp
src/ToolBox/superpmi/superpmi/jithost.h
src/ToolBox/superpmi/superpmi/jitinstance.cpp
src/ToolBox/superpmi/superpmi/jitinstance.h
src/ToolBox/superpmi/superpmi/superpmi.cpp
src/jit/ee_il_dll.cpp

index b33e031..eb3b189 100644 (file)
@@ -6061,3 +6061,46 @@ OnError:
 
 #endif // !FEATURE_PAL
 }
+
+DenseLightWeightMap<MethodContext::Agnostic_Environment>* MethodContext::prevEnviroment = nullptr;
+
+bool MethodContext::wasEnviromentChanged()
+{
+    bool changed = false;
+    if (prevEnviroment == nullptr)
+    {
+        changed = true;
+    }
+    else if (Environment->GetCount() != prevEnviroment->GetCount())
+    {
+        changed = true;
+    }
+    else
+    {
+        for (unsigned int i = 0; i < Environment->GetCount(); i++)
+        {
+            Agnostic_Environment currEnvValue = Environment->Get(i);
+            LPCSTR currKey = (LPCSTR)Environment->GetBuffer(currEnvValue.name_index);
+            LPCSTR currVal = (LPCSTR)Environment->GetBuffer(currEnvValue.val_index);
+
+            Agnostic_Environment prevEnvValue = prevEnviroment->Get(i);
+            LPCSTR prevKey = (LPCSTR)prevEnviroment->GetBuffer(prevEnvValue.name_index);
+            LPCSTR prevVal = (LPCSTR)prevEnviroment->GetBuffer(prevEnvValue.val_index);
+            if (strcmp(currKey, prevKey) != 0 || strcmp(currVal, prevVal) != 0)
+            {
+                changed = true;
+                break;
+            }
+        }
+    }
+    if (changed)
+    {
+        if (prevEnviroment == nullptr)
+        {
+            delete prevEnviroment;
+        }
+        prevEnviroment = new DenseLightWeightMap<Agnostic_Environment>(*Environment);
+        return true;
+    }
+    return false;
+}
index d2f43b4..83c1677 100644 (file)
@@ -1233,6 +1233,9 @@ public:
     void dmpGetStringConfigValue(DWORD nameIndex, DWORD result);
     const wchar_t* repGetStringConfigValue(const wchar_t* name);
 
+    bool wasEnviromentChanged();
+    static DenseLightWeightMap<Agnostic_Environment>* prevEnviroment;
+
     CompileResult* cr;
     CompileResult* originalCR;
     int            index;
index 6b40839..8d1930f 100644 (file)
@@ -121,6 +121,10 @@ MethodContextReader::MethodContextReader(
 
 MethodContextReader::~MethodContextReader()
 {
+    if (MethodContext::prevEnviroment != nullptr)
+    {
+        delete MethodContext::prevEnviroment;
+    }
     if (fileHandle != INVALID_HANDLE_VALUE)
     {
         CloseHandle(this->fileHandle);
index 60181cd..9e31e43 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef _JITHOST
 #define _JITHOST
 
-class JitHost : public ICorJitHost
+class JitHost final: public ICorJitHost
 {
 public:
     JitHost(JitInstance& jitInstance);
index e463f82..7902c39 100644 (file)
@@ -429,3 +429,18 @@ void JitInstance::freeLongLivedArray(void* array)
 {
     HeapFree(ourHeap, 0, array);
 }
+
+// Reset JitConfig, that stores Enviroment variables.
+bool JitInstance::resetConfig(MethodContext* firstContext)
+{
+    if (pnjitStartup != nullptr)
+    {
+        mc = firstContext;
+        ICorJitHost* newHost = new JitHost(*this);
+        pnjitStartup(newHost);
+        delete static_cast<JitHost*>(jitHost);
+        jitHost = newHost;
+        return true;
+    }
+    return false;
+}
index 9db17dc..3b4d22c 100644 (file)
@@ -46,6 +46,8 @@ public:
     HRESULT StartUp(char* PathToJit, bool copyJit, bool breakOnDebugBreakorAV, MethodContext* firstContext);
     bool reLoad(MethodContext* firstContext);
 
+    bool resetConfig(MethodContext* firstContext);
+
     Result CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput);
 
     void* allocateArray(ULONG size);
index 58d7787..c98c053 100644 (file)
@@ -313,6 +313,21 @@ int __cdecl main(int argc, char* argv[])
         mc->cr         = new CompileResult();
         mc->originalCR = crl;
 
+        if (mc->wasEnviromentChanged())
+        {
+            if (!jit->resetConfig(mc))
+            {
+                LogError("JIT can't reset enviroment");
+            }
+            if (o.nameOfJit2 != nullptr)
+            {
+                if (!jit2->resetConfig(mc))
+                {
+                    LogError("JIT2 can't reset enviroment");
+                }
+            }
+        }
+
         jittedCount++;
         st3.Start();
         res = jit->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput);
index 553a9b8..b32d59f 100644 (file)
@@ -58,6 +58,20 @@ extern "C" void __stdcall jitStartup(ICorJitHost* jitHost)
 {
     if (g_jitInitialized)
     {
+        if (jitHost != g_jitHost)
+        {
+            // We normally don't expect jitStartup() to be invoked more than once.
+            // (We check whether it has been called once due to an abundance of caution.)
+            // However, during SuperPMI playback of MCH file, we need to JIT many different methods.
+            // Each one carries its own environment configuration state.
+            // So, we need the JIT to reload the JitConfig state for each change in the environment state of the
+            // replayed compilations.
+            // We do this by calling jitStartup with a different ICorJitHost,
+            // and have the JIT re-initialize its JitConfig state when this happens.
+            JitConfig.destroy(g_jitHost);
+            JitConfig.initialize(jitHost);
+            g_jitHost = jitHost;
+        }
         return;
     }