Add the capability to specify JIT options on the SPMI command line.
authorPat Gavlin <pagavlin@microsoft.com>
Sat, 29 Jul 2017 22:42:39 +0000 (15:42 -0700)
committerPat Gavlin <pagavlin@microsoft.com>
Thu, 7 Sep 2017 23:17:21 +0000 (16:17 -0700)
This change adds two new flags, `-jitoption` and `-jit2option`, to the
SuperPMI command line. These flags are cumulative, and are used to
specify JIT config options (e.g. `COMPlus_JitDisasm`, albeit without the
`COMPlus_` prefix) to the base and diff JITs, respectively.

This change also removes Smarty-specific code and support for capturing
and replaying environment variables. The former is no longer terribly
useful and the latter has been obviated by the JIT host interface.

16 files changed:
src/ToolBox/superpmi/mcs/CMakeLists.txt
src/ToolBox/superpmi/mcs/commandline.cpp
src/ToolBox/superpmi/mcs/commandline.h
src/ToolBox/superpmi/mcs/mcs.cpp
src/ToolBox/superpmi/mcs/verbsmarty.cpp [deleted file]
src/ToolBox/superpmi/mcs/verbsmarty.h [deleted file]
src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
src/ToolBox/superpmi/superpmi-shared/methodcontext.h
src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp
src/ToolBox/superpmi/superpmi/commandline.cpp
src/ToolBox/superpmi/superpmi/commandline.h
src/ToolBox/superpmi/superpmi/jithost.cpp
src/ToolBox/superpmi/superpmi/jitinstance.cpp
src/ToolBox/superpmi/superpmi/jitinstance.h
src/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
src/ToolBox/superpmi/superpmi/superpmi.cpp

index 6ad1ff3..ebacd07 100644 (file)
@@ -24,7 +24,6 @@ set(MCS_SOURCES
     verbinteg.cpp
     verbmerge.cpp
     verbremovedup.cpp
-    verbsmarty.cpp
     verbstat.cpp
     verbstrip.cpp
     verbtoc.cpp
index cc2244d..1611228 100644 (file)
@@ -107,10 +107,6 @@ void CommandLine::DumpHelp(const char* program)
     printf("     e.g. -removeDup -thin a.mc b.mc\n");
     printf("     e.g. -removeDup -legacy -thin a.mc b.mc\n");
     printf("\n");
-    printf(" -smarty range inputfile outputfile\n");
-    printf("     Write smarty Test IDs of the range from inputfile to outputfile.\n");
-    printf("     e.g. -smarty 2 a.mc b.mc\n");
-    printf("\n");
     printf(" -stat {optional range} inputfile outputfile\n");
     printf("     Report various statistics per method context.\n");
     printf("     inputfile is read and statistics are written into outputfile\n");
@@ -344,14 +340,6 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
             {
                 o->legacyCompare = true;
             }
-            else if ((_strnicmp(&argv[i][1], "smarty", argLen) == 0))
-            {
-                tempLen         = strlen(argv[i]);
-                o->actionSmarty = true;
-                foundVerb       = true;
-                if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next
-                    goto processMCL;
-            }
             else if ((_strnicmp(&argv[i][1], "verbosity", argLen) == 0))
             {
                 if (++i >= argc)
@@ -564,16 +552,6 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
         }
         return true;
     }
-    if (o->actionSmarty)
-    {
-        if ((!foundFile1) || (!foundFile2))
-        {
-            LogError("CommandLine::Parse() '-smarty' needs one input file and one output file.");
-            DumpHelp(argv[0]);
-            return false;
-        }
-        return true;
-    }
 
     DumpHelp(argv[0]);
     return false;
index 442f2a4..4e59493 100644 (file)
@@ -27,7 +27,6 @@ public:
             , actionInteg(false)
             , actionMerge(false)
             , actionRemoveDup(false)
-            , actionSmarty(false)
             , actionStat(false)
             , actionStrip(false)
             , actionTOC(false)
@@ -53,7 +52,6 @@ public:
         bool  actionInteg;
         bool  actionMerge;
         bool  actionRemoveDup;
-        bool  actionSmarty;
         bool  actionStat;
         bool  actionStrip;
         bool  actionTOC;
index 7026ff5..4ed72ca 100644 (file)
@@ -19,7 +19,6 @@
 #include "verbconcat.h"
 #include "verbmerge.h"
 #include "verbstrip.h"
-#include "verbsmarty.h"
 #include "logging.h"
 
 int __cdecl main(int argc, char* argv[])
@@ -98,10 +97,6 @@ int __cdecl main(int argc, char* argv[])
     {
         exitCode = verbTOC::DoWork(o.nameOfFile1);
     }
-    if (o.actionSmarty)
-    {
-        exitCode = verbSmarty::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes);
-    }
 
     Logger::Shutdown();
     return exitCode;
diff --git a/src/ToolBox/superpmi/mcs/verbsmarty.cpp b/src/ToolBox/superpmi/mcs/verbsmarty.cpp
deleted file mode 100644 (file)
index a9425bd..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-#include "standardpch.h"
-#include "verbsmarty.h"
-#include "simpletimer.h"
-#include "methodcontext.h"
-#include "methodcontextiterator.h"
-
-//
-// Constructs a new verbSmarty.
-//
-// Arguments:
-//    hFile  - A handle to the output file that we are writing the Smarty Test IDs
-//
-// Assumptions:
-//    hFile refers to an open and writeable file handle.
-//
-verbSmarty::verbSmarty(HANDLE hFile)
-{
-    m_hFile = hFile;
-}
-
-//
-// Dumps the Smarty TestID to file
-//
-// Arguments:
-//    testID    - Smarty Test ID
-//
-void verbSmarty::DumpTestInfo(int testID)
-{
-#define bufflen 4096
-    DWORD bytesWritten;
-
-    char buff[bufflen];
-    int  buff_offset = 0;
-    ZeroMemory(buff, bufflen * sizeof(char));
-
-    buff_offset += sprintf_s(&buff[buff_offset], bufflen - buff_offset, "%i\r\n", testID);
-    WriteFile(m_hFile, buff, buff_offset * sizeof(char), &bytesWritten, nullptr);
-}
-
-int verbSmarty::DoWork(const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes)
-{
-    LogVerbose("Reading from '%s' reading Smarty ID for the Mc Indexes and writing into '%s'", nameOfInput,
-               nameOfOutput);
-
-    MethodContextIterator mci(indexCount, indexes);
-    if (!mci.Initialize(nameOfInput))
-        return -1;
-
-    int savedCount = 0;
-
-    HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
-                                  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
-    if (hFileOut == INVALID_HANDLE_VALUE)
-    {
-        LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError());
-        return -1;
-    }
-
-    verbSmarty* verbList = new verbSmarty(hFileOut);
-
-    // TODO-Cleanup: look to use toc for this
-    while (mci.MoveNext())
-    {
-        MethodContext* mc = mci.Current();
-
-        int testID = mc->repGetTestID();
-        if (testID != -1)
-        {
-            // write to the file
-            verbList->DumpTestInfo(testID);
-        }
-        else
-        {
-            LogError("Smarty ID not found for '%s'", mc->cr->repProcessName());
-        }
-    }
-
-    delete verbList;
-
-    if (!CloseHandle(hFileOut))
-    {
-        LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError());
-        return -1;
-    }
-
-    LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount);
-
-    if (!mci.Destroy())
-        return -1;
-
-    return 0;
-}
diff --git a/src/ToolBox/superpmi/mcs/verbsmarty.h b/src/ToolBox/superpmi/mcs/verbsmarty.h
deleted file mode 100644 (file)
index c595ecb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-//----------------------------------------------------------
-// verbSmarty.h - verb that outputs Smarty test ID for mc
-//----------------------------------------------------------
-#ifndef _verbSmarty
-#define _verbSmarty
-
-class verbSmarty
-{
-public:
-    verbSmarty(HANDLE hFile);
-    void DumpTestInfo(int testID);
-    static int DoWork(const char* nameOfInput, const char* nameofOutput, int indexCount, const int* indexes);
-
-private:
-    HANDLE m_hFile;
-};
-#endif
index 1545056..7696560 100644 (file)
@@ -481,7 +481,7 @@ bool MethodContext::Equal(MethodContext* other)
 //    `ICJI::compileMethod`).
 //
 //    This method is intended to be called as part of initializing a method
-//    during collection, similar to `methodContext::recEnvironment`.
+//    during collection.
 void MethodContext::recGlobalContext(const MethodContext& other)
 {
     Assert(GetIntConfigValue == nullptr);
@@ -498,128 +498,8 @@ void MethodContext::recGlobalContext(const MethodContext& other)
     }
 }
 
-void MethodContext::recEnvironment()
-{
-    if (Environment == nullptr)
-        Environment = new DenseLightWeightMap<Agnostic_Environment>();
-
-    char* l_EnvStr;
-    char* l_val;
-
-#ifdef FEATURE_PAL
-    l_EnvStr = GetEnvironmentStringsA();
-#else  // !FEATURE_PAL
-    l_EnvStr = GetEnvironmentStrings();
-#endif // !FEATURE_PAL
-
-    l_val = l_EnvStr;
-
-    char* l_str = l_EnvStr;
-
-    int count = 0;
-    while (true)
-    {
-        if (*l_str == 0)
-            break;
-        while (*l_str != 0)
-            l_str++;
-        l_str++;
-        count++;
-    }
-
-    for (int i = 0; i < count; i++)
-    {
-        if ((_strnicmp(l_EnvStr, "complus_", 8) == 0) || (_strnicmp(l_EnvStr, "dbflag", 6) == 0) ||
-            (_strnicmp(l_EnvStr, "BVT_TEST_ID", 11) == 0))
-        {
-            char* val = l_EnvStr;
-            while (*val != '=')
-                val++;
-            *val++                       = 0;
-            int                  nameind = Environment->AddBuffer((unsigned char*)l_EnvStr, (int)strlen(l_EnvStr) + 1);
-            int                  valind  = Environment->AddBuffer((unsigned char*)val, (int)strlen(val) + 1);
-            Agnostic_Environment value;
-            value.name_index = nameind;
-            value.val_index  = valind;
-            DWORD key        = (DWORD)Environment->GetCount();
-            Environment->Append(value);
-            DEBUG_REC(dmpEnvironment(key, value));
-            l_EnvStr = val;
-        }
-        while (*l_EnvStr != '\0')
-            l_EnvStr++;
-        l_EnvStr++;
-    }
-    FreeEnvironmentStringsA(l_val);
-}
 void MethodContext::dmpEnvironment(DWORD key, const Agnostic_Environment& value)
 {
-    printf("Environment key %u, value '%s' '%s'", key, (LPCSTR)Environment->GetBuffer(value.name_index),
-           (LPCSTR)Environment->GetBuffer(value.val_index));
-    Environment->Unlock();
-}
-void MethodContext::repEnvironmentSet()
-{
-    if (Environment == nullptr)
-        return;
-    Agnostic_Environment val;
-    for (unsigned int i = 0; i < Environment->GetCount(); i++)
-    {
-        val = Environment->Get((DWORD)i);
-        DEBUG_REP(dmpEnvironment(i, val));
-
-        SetEnvironmentVariableA((LPCSTR)Environment->GetBuffer(val.name_index),
-                                (LPCSTR)Environment->GetBuffer(val.val_index));
-    }
-}
-
-int MethodContext::repGetTestID()
-{
-    // CLR Test asset only - we capture the testID via smarty-environnent (BVT_TEST_ID) during record time
-    // This procedure returns the test id if found and -1 otherwise
-
-    if (Environment == nullptr)
-        return -1;
-    Agnostic_Environment val;
-    LPCSTR               key;
-    int                  value = -1;
-    for (unsigned int i = 0; i < Environment->GetCount(); i++)
-    {
-        val = Environment->Get((DWORD)i);
-        key = (LPCSTR)Environment->GetBuffer(val.name_index);
-
-        if (_strnicmp(key, "BVT_TEST_ID", 11) == 0)
-        {
-            value = atoi((LPCSTR)Environment->GetBuffer(val.val_index));
-            break;
-        }
-    }
-
-    if (value == -1)
-    {
-        LogError("Couldn't find Smarty test ID");
-    }
-
-    return value;
-}
-
-void MethodContext::repEnvironmentUnset()
-{
-    if (Environment == nullptr)
-        return;
-    Agnostic_Environment val;
-    for (unsigned int i = 0; i < Environment->GetCount(); i++)
-    {
-        val = Environment->Get((DWORD)i);
-        SetEnvironmentVariableA((LPCSTR)Environment->GetBuffer(val.name_index), nullptr);
-    }
-}
-int MethodContext::repEnvironmentGetCount()
-{
-    int result = 0;
-    if (Environment != nullptr)
-        result = Environment->GetCount();
-    return result;
 }
 
 void MethodContext::dumpToConsole(int mcNumber)
@@ -5974,15 +5854,6 @@ const wchar_t* MethodContext::repGetStringConfigValue(const wchar_t* name)
     return value;
 }
 
-struct EnvironmentVariable
-{
-    char* name;
-    DWORD val_index;
-};
-int __cdecl compareEnvironmentVariable(const void* arg1, const void* arg2)
-{
-    return _stricmp(((EnvironmentVariable*)arg1)->name, ((EnvironmentVariable*)arg2)->name);
-}
 int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len)
 {
     char* obuff = buff;
@@ -6007,46 +5878,6 @@ int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len)
     buff += t;
     len -= t;
 
-    // Add COMPLUS_* & dbflag environment variables to method Identity
-    // except complus_version and complus_defaultversion
-    // since they change the compilation behaviour of JIT
-    // we also need to sort them to ensure we don't produce a different
-    // hash based on the order of these variables
-    if (Environment != nullptr)
-    {
-        Agnostic_Environment val;
-        EnvironmentVariable* envValues   = new EnvironmentVariable[Environment->GetCount()];
-        int                  envValCount = 0;
-
-        for (unsigned int i = 0; i < Environment->GetCount(); i++)
-        {
-            val               = Environment->Get((DWORD)i);
-            char* envVariable = (char*)Environment->GetBuffer(val.name_index);
-            if ((_strnicmp(envVariable, "complus_", 8) == 0 || _strnicmp(envVariable, "dbflag", 6) == 0) &&
-                (_stricmp(envVariable, "complus_version") != 0) &&
-                (_stricmp(envVariable, "complus_defaultversion") != 0))
-            {
-                envValues[envValCount].name        = envVariable;
-                envValues[envValCount++].val_index = val.val_index;
-            }
-        }
-
-        // Do a quick sort on envValues if needed
-        if (envValCount > 1)
-            qsort(envValues, envValCount, sizeof(EnvironmentVariable), compareEnvironmentVariable);
-
-        // Append these values to the IdentityInfobuffer
-        for (int i = 0; i < envValCount; i++)
-        {
-            t = sprintf_s(buff, len, "%s=%s ", _strlwr(envValues[i].name),
-                          _strlwr((char*)Environment->GetBuffer(envValues[i].val_index)));
-            buff += t;
-            len -= t;
-        }
-
-        delete[] envValues;
-    }
-
     // Hash the IL Code for this method and append it to the ID info
     char ilHash[MD5_HASH_BUFFER_SIZE];
     dumpMD5HashToBuffer(info.ILCode, info.ILCodeSize, ilHash, MD5_HASH_BUFFER_SIZE);
index eec4031..7f79b2b 100644 (file)
@@ -570,12 +570,7 @@ public:
 
     void recGlobalContext(const MethodContext& other);
 
-    void recEnvironment();
     void dmpEnvironment(DWORD key, const Agnostic_Environment& value);
-    void repEnvironmentSet();
-    void repEnvironmentUnset();
-    int  repEnvironmentGetCount();
-    int  repGetTestID();
 
     void recCompileMethod(CORINFO_METHOD_INFO* info, unsigned flags);
     void dmpCompileMethod(DWORD key, const Agnostic_CompileMethod& value);
@@ -1287,7 +1282,7 @@ enum mcPackets
     Packet_EmbedMethodHandle                             = 19,
     Packet_EmbedModuleHandle                             = 20,
     Packet_EmptyStringLiteral                            = 21,
-    Packet_Environment                                   = 136, // Added 4/3/2013
+    Packet_Environment                                   = 136, // Deprecated 7/29/2017
     Packet_ErrorList                                     = 22,
     Packet_FilterException                               = 134,
     Packet_FindCallSiteSig                               = 23,
index eaa6b8c..19f9638 100644 (file)
@@ -63,9 +63,6 @@ CorJitResult __stdcall interceptor_ICJC::compileMethod(ICorJitInfo*
         our_ICorJitInfo.mc->recGlobalContext(*g_globalContext);
     }
 
-    // Record a simple view of the environment
-    our_ICorJitInfo.mc->recEnvironment();
-
     CorJitResult temp =
         original_ICorJitCompiler->compileMethod(&our_ICorJitInfo, info, flags, nativeEntry, nativeSizeOfCode);
 
index c77337f..47ba094 100644 (file)
@@ -8,6 +8,7 @@
 //----------------------------------------------------------
 
 #include "standardpch.h"
+#include "lightweightmap.h"
 #include "commandline.h"
 #include "superpmi.h"
 #include "mclist.h"
@@ -116,7 +117,13 @@ void CommandLine::DumpHelp(const char* program)
     printf("     Ignored: MSVCDIS is not available, so CoreDisTools will be used.\n");
 #else
     printf("     Ignored: neither MSVCDIS nor CoreDisTools is available.\n");
-#endif
+#endif // USE_COREDISTOOLS
+    printf("\n");
+    printf(" -jitoption key=value\n");
+    printf("     Set the JIT option named \"key\" to \"value\" for JIT 1. NOTE: do not use a \"COMPlus_\" prefix!\n");
+    printf("\n");
+    printf(" -jit2option key=value\n");
+    printf("     Set the JIT option named \"key\" to \"value\" for JIT 2. NOTE: do not use a \"COMPlus_\" prefix!\n");
     printf("\n");
     printf("Inputs are case sensitive.\n");
     printf("\n");
@@ -140,6 +147,40 @@ void CommandLine::DumpHelp(const char* program)
     printf("     ; if there are any failures, record their MC numbers in the file fail.mcl\n");
 }
 
+static bool ParseJitOption(const char* optionString, wchar_t** key, wchar_t **value)
+{
+    char tempKey[1024];
+
+    unsigned i;
+    for (i = 0; optionString[i] != '='; i++)
+    {
+        if ((i >= 1023) || (optionString[i] == '\0'))
+        {
+            return false;
+        }
+        tempKey[i] = optionString[i];
+    }
+    tempKey[i] = '\0';
+
+    const char* tempVal = &optionString[i + 1];
+    if (tempVal[0] == '\0')
+    {
+        return false;
+    }
+
+    const unsigned keyLen = i;
+    wchar_t* keyBuf = new wchar_t[keyLen + 1];
+    MultiByteToWideChar(CP_UTF8, 0, tempKey, keyLen + 1, keyBuf, keyLen + 1);
+
+    const unsigned valLen = (unsigned)strlen(tempVal);
+    wchar_t* valBuf = new wchar_t[valLen + 1];
+    MultiByteToWideChar(CP_UTF8, 0, tempVal, valLen + 1, valBuf, valLen + 1);
+
+    *key = keyBuf;
+    *value = valBuf;
+    return true;
+}
+
 // Assumption: All inputs are initialized to default or real value.  we'll just set the stuff we see on the command
 // line. Assumption: Single byte names are passed in.. mb stuff doesnt cause an obvious problem... but it might have
 // issues... Assumption: Values larger than 2^31 aren't expressible from the commandline.... (atoi) Unless you pass in
@@ -481,6 +522,52 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
                     return false;
                 }
             }
+            else if ((_strnicmp(&argv[i][1], "jitoption", argLen) == 0))
+            {
+                i++;
+
+                wchar_t *key, *value;
+                if ((i >= argc) || !ParseJitOption(argv[i], &key, &value))
+                {
+                    DumpHelp(argv[0]);
+                    return false;
+                }
+
+                if (o->jitOptions == nullptr)
+                {
+                    o->jitOptions = new LightWeightMap<DWORD, DWORD>();
+                }
+
+                DWORD keyIndex = (DWORD)o->jitOptions->AddBuffer((unsigned char*)key, sizeof(wchar_t) * ((unsigned int)wcslen(key) + 1));
+                DWORD valueIndex = (DWORD)o->jitOptions->AddBuffer((unsigned char*)value, sizeof(wchar_t) * ((unsigned int)wcslen(value) + 1));
+                o->jitOptions->Add(keyIndex, valueIndex);
+
+                delete[] key;
+                delete[] value;
+            }
+            else if ((_strnicmp(&argv[i][1], "jit2option", argLen) == 0))
+            {
+                i++;
+
+                wchar_t *key, *value;
+                if ((i >= argc) || !ParseJitOption(argv[i], &key, &value))
+                {
+                    DumpHelp(argv[0]);
+                    return false;
+                }
+
+                if (o->jit2Options == nullptr)
+                {
+                    o->jit2Options = new LightWeightMap<DWORD, DWORD>();
+                }
+
+                DWORD keyIndex = (DWORD)o->jit2Options->AddBuffer((unsigned char*)key, sizeof(wchar_t) * ((unsigned int)wcslen(key) + 1));
+                DWORD valueIndex = (DWORD)o->jit2Options->AddBuffer((unsigned char*)value, sizeof(wchar_t) * ((unsigned int)wcslen(value) + 1));
+                o->jit2Options->Add(keyIndex, valueIndex);
+
+                delete[] key;
+                delete[] value;
+            }
             else
             {
                 LogError("Unknown switch '%s' passed as argument.", argv[i]);
index 8703447..0881f08 100644 (file)
@@ -42,6 +42,8 @@ public:
             , compileList(nullptr)
             , offset(-1)
             , increment(-1)
+            , jitOptions(nullptr)
+            , jit2Options(nullptr)
         {
         }
 
@@ -67,6 +69,8 @@ public:
         char* compileList;
         int   offset;
         int   increment;
+        LightWeightMap<DWORD, DWORD>* jitOptions;
+        LightWeightMap<DWORD, DWORD>* jit2Options;
     };
 
     static bool Parse(int argc, char* argv[], /* OUT */ Options* o);
index d14909b..a515d51 100644 (file)
@@ -77,19 +77,30 @@ int JitHost::getIntConfigValue(const wchar_t* key, int defaultValue)
         return jitInstance.mc->index;
     }
 
-    // If the result is the default value, probe the environment for
-    // a COMPlus variable with the same name.
-    wchar_t* complus = GetCOMPlusVariable(key, jitInstance);
-    if (complus == nullptr)
-    {
-        return defaultValue;
-    }
+    // If the result is the default value, probe the JIT options and then the environment. If a value is found, parse
+    // it as a hex integer.
 
-    // Parse the value as a hex integer.
     wchar_t* endPtr;
-    result         = static_cast<int>(wcstoul(complus, &endPtr, 16));
-    bool succeeded = (errno != ERANGE) && (endPtr != complus);
-    jitInstance.freeLongLivedArray(complus);
+    bool     succeeded;
+
+    const wchar_t* value = jitInstance.getOption(key);
+    if (value != nullptr)
+    {
+        result    = static_cast<int>(wcstoul(value, &endPtr, 16));
+        succeeded = (errno != ERANGE) && (endPtr != value);
+    }
+    else
+    {
+        wchar_t* complus = GetCOMPlusVariable(key, jitInstance);
+        if (complus == nullptr)
+        {
+            return defaultValue;
+        }
+
+        result    = static_cast<int>(wcstoul(complus, &endPtr, 16));
+        succeeded = (errno != ERANGE) && (endPtr != complus);
+        jitInstance.freeLongLivedArray(complus);
+    }
 
     return succeeded ? result : defaultValue;
 }
@@ -99,19 +110,22 @@ const wchar_t* JitHost::getStringConfigValue(const wchar_t* key)
     jitInstance.mc->cr->AddCall("getStringConfigValue");
     const wchar_t* result = jitInstance.mc->repGetStringConfigValue(key);
 
-    if (result != nullptr)
+    // If the result is the default value, probe the JIT options and then the environment.
+    if (result == nullptr)
     {
-        // Now we need to dup it, so you can call freeStringConfigValue() on what we return.
-        size_t   resultLenInChars = wcslen(result) + 1;
-        wchar_t* dupResult = (wchar_t*)jitInstance.allocateLongLivedArray((ULONG)(sizeof(wchar_t) * resultLenInChars));
-        wcscpy_s(dupResult, resultLenInChars, result);
-
-        return dupResult;
+        result = jitInstance.getOption(key);
+        if (result == nullptr)
+        {
+            return GetCOMPlusVariable(key, jitInstance);
+        }
     }
 
-    // If the result is the default value, probe the environment for
-    // a COMPlus variable with the same name.
-    return GetCOMPlusVariable(key, jitInstance);
+    // Now we need to dup it, so you can call freeStringConfigValue() on what we return.
+    size_t   resultLenInChars = wcslen(result) + 1;
+    wchar_t* dupResult = (wchar_t*)jitInstance.allocateLongLivedArray((ULONG)(sizeof(wchar_t) * resultLenInChars));
+    wcscpy_s(dupResult, resultLenInChars, result);
+
+    return dupResult;
 }
 
 void JitHost::freeStringConfigValue(const wchar_t* value)
index 7902c39..2d84cfd 100644 (file)
@@ -12,7 +12,7 @@
 #include "errorhandling.h"
 #include "spmiutil.h"
 
-JitInstance* JitInstance::InitJit(char* nameOfJit, bool breakOnAssert, SimpleTimer* st1, MethodContext* firstContext)
+JitInstance* JitInstance::InitJit(char* nameOfJit, bool breakOnAssert, SimpleTimer* st1, MethodContext* firstContext, LightWeightMap<DWORD, DWORD>* options)
 {
     JitInstance* jit = new JitInstance();
     if (jit == nullptr)
@@ -21,6 +21,8 @@ JitInstance* JitInstance::InitJit(char* nameOfJit, bool breakOnAssert, SimpleTim
         return nullptr;
     }
 
+    jit->options = options;
+
     if (st1 != nullptr)
         st1->Start();
     HRESULT hr = jit->StartUp(nameOfJit, false, breakOnAssert, firstContext);
@@ -33,6 +35,7 @@ JitInstance* JitInstance::InitJit(char* nameOfJit, bool breakOnAssert, SimpleTim
     }
     if (st1 != nullptr)
         LogVerbose("Jit startup took %fms", st1->GetMilliseconds());
+
     return jit;
 }
 
@@ -284,7 +287,6 @@ JitInstance::Result JitInstance::CompileMethod(MethodContext* MethodToCompile, i
     times[0] = 0;
     times[1] = 0;
 
-    mc->repEnvironmentSet(); // Sets envvars
     stj.Start();
 
     PAL_TRY(Param*, pParam, &param)
@@ -349,7 +351,6 @@ JitInstance::Result JitInstance::CompileMethod(MethodContext* MethodToCompile, i
         // If we get here, we know it compiles
         timeResult(param.info, param.flags);
     }
-    mc->repEnvironmentUnset(); // Unsets envvars
 
     mc->cr->secondsToCompile = stj.GetSeconds();
 
@@ -398,6 +399,23 @@ void JitInstance::timeResult(CORINFO_METHOD_INFO info, unsigned flags)
 
 /*-------------------------- Misc ---------------------------------------*/
 
+const wchar_t* JitInstance::getOption(const wchar_t* key)
+{
+    if (options == nullptr)
+    {
+        return nullptr;
+    }
+
+    size_t keyLenInBytes = sizeof(wchar_t) * (wcslen(key) + 1);
+    int    keyIndex      = options->Contains((unsigned char*)key, (unsigned int)keyLenInBytes);
+    if (keyIndex == -1)
+    {
+        return nullptr;
+    }
+
+    return (const wchar_t*)options->GetBuffer(options->Get(keyIndex));
+}
+
 // Used to allocate memory that needs to handed to the EE.
 // For eg, use this to allocated memory for reporting debug info,
 // which will be handed to the EE by setVars() and setBoundaries()
index 3b4d22c..0baf401 100644 (file)
@@ -25,6 +25,8 @@ private:
     ICorJitInfo*   icji;
     SimpleTimer    stj;
 
+    LightWeightMap<DWORD, DWORD>* options;
+
     JitInstance(){};
     void timeResult(CORINFO_METHOD_INFO info, unsigned flags);
 
@@ -41,7 +43,7 @@ public:
     ICorJitCompiler* pJitInstance;
 
     // Allocate and initialize the jit provided
-    static JitInstance* InitJit(char* nameOfJit, bool breakOnAssert, SimpleTimer* st1, MethodContext* firstContext);
+    static JitInstance* InitJit(char* nameOfJit, bool breakOnAssert, SimpleTimer* st1, MethodContext* firstContext, LightWeightMap<DWORD, DWORD>* options);
 
     HRESULT StartUp(char* PathToJit, bool copyJit, bool breakOnDebugBreakorAV, MethodContext* firstContext);
     bool reLoad(MethodContext* firstContext);
@@ -50,6 +52,8 @@ public:
 
     Result CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput);
 
+    const wchar_t* getOption(const wchar_t* key);
+
     void* allocateArray(ULONG size);
     void* allocateLongLivedArray(ULONG size);
     void freeArray(void* array);
index 0f2d31d..41b27de 100644 (file)
@@ -7,6 +7,7 @@
 #include "superpmi.h"
 #include "simpletimer.h"
 #include "mclist.h"
+#include "lightweightmap.h"
 #include "commandline.h"
 #include "errorhandling.h"
 
@@ -360,6 +361,26 @@ char* ConstructChildProcessArgs(const CommandLine::Options& o)
     ADDARG_STRING(o.targetArchitecture, "-target");
     ADDARG_STRING(o.compileList, "-compile");
 
+    if (o.jitOptions != nullptr)
+    {
+        for (unsigned i = 0; i < o.jitOptions->GetCount(); i++)
+        {
+            wchar_t* key = (wchar_t*)o.jitOptions->GetBuffer(o.jitOptions->GetKey(i));
+            wchar_t* value = (wchar_t*)o.jitOptions->GetBuffer(o.jitOptions->GetItem(i));
+            bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -jitoption %S=%S", key, value);
+        }
+    }
+
+    if (o.jit2Options != nullptr)
+    {
+        for (unsigned i = 0; i < o.jit2Options->GetCount(); i++)
+        {
+            wchar_t* key = (wchar_t*)o.jit2Options->GetBuffer(o.jit2Options->GetKey(i));
+            wchar_t* value = (wchar_t*)o.jit2Options->GetBuffer(o.jit2Options->GetItem(i));
+            bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -jit2option %S=%S", key, value);
+        }
+    }
+
     ADDSTRING(o.nameOfJit);
     ADDSTRING(o.nameOfJit2);
     ADDSTRING(o.nameOfInputMethodContextFile);
index c98c053..a8363a6 100644 (file)
@@ -9,6 +9,7 @@
 #include "coredistools.h"
 #endif // USE_COREDISTOOLS
 
+#include "lightweightmap.h"
 #include "commandline.h"
 #include "superpmi.h"
 #include "jitinstance.h"
@@ -106,8 +107,8 @@ void InvokeNearDiffer(NearDiffer*           nearDiffer,
     {
         SpmiException e(&param.exceptionPointers);
 
-        LogError("main method %d of size %d failed to load and compile correctly. EnvCnt=%d",
-                 (*reader)->GetMethodContextIndex(), (*mc)->methodSize, (*mc)->repEnvironmentGetCount());
+        LogError("main method %d of size %d failed to load and compile correctly.",
+                 (*reader)->GetMethodContextIndex(), (*mc)->methodSize);
         e.ShowAndDeleteMessage();
         if ((*o).mclFilename != nullptr)
             (*failingMCL).AddMethodToMCL((*reader)->GetMethodContextIndex());
@@ -286,7 +287,7 @@ int __cdecl main(int argc, char* argv[])
         {
             SimpleTimer st4;
 
-            jit = JitInstance::InitJit(o.nameOfJit, o.breakOnAssert, &st4, mc);
+            jit = JitInstance::InitJit(o.nameOfJit, o.breakOnAssert, &st4, mc, o.jitOptions);
             if (jit == nullptr)
             {
                 // InitJit already printed a failure message
@@ -295,7 +296,7 @@ int __cdecl main(int argc, char* argv[])
 
             if (o.nameOfJit2 != nullptr)
             {
-                jit2 = JitInstance::InitJit(o.nameOfJit2, o.breakOnAssert, &st4, mc);
+                jit2 = JitInstance::InitJit(o.nameOfJit2, o.breakOnAssert, &st4, mc, o.jit2Options);
                 if (jit2 == nullptr)
                 {
                     // InitJit already printed a failure message
@@ -360,8 +361,8 @@ int __cdecl main(int argc, char* argv[])
 
             if (res2 == JitInstance::RESULT_ERROR)
             {
-                LogError("JIT2 main method %d of size %d failed to load and compile correctly. EnvCnt=%d",
-                         reader->GetMethodContextIndex(), mc->methodSize, mc->repEnvironmentGetCount());
+                LogError("JIT2 main method %d of size %d failed to load and compile correctly.",
+                         reader->GetMethodContextIndex(), mc->methodSize);
             }
 
             // Methods that don't compile due to missing JIT-EE information
@@ -503,8 +504,8 @@ int __cdecl main(int argc, char* argv[])
             // to, for instance, failures caused by missing JIT-EE details).
             if (res == JitInstance::RESULT_ERROR)
             {
-                LogError("main method %d of size %d failed to load and compile correctly. EnvCnt=%d",
-                         reader->GetMethodContextIndex(), mc->methodSize, mc->repEnvironmentGetCount());
+                LogError("main method %d of size %d failed to load and compile correctly.",
+                         reader->GetMethodContextIndex(), mc->methodSize);
                 if ((o.reproName != nullptr) && (o.indexCount == -1))
                 {
                     char buff[500];