diff options
Diffstat (limited to 'src/jit/jitconfig.cpp')
-rw-r--r-- | src/jit/jitconfig.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/jit/jitconfig.cpp b/src/jit/jitconfig.cpp new file mode 100644 index 0000000000..9f0e226e3a --- /dev/null +++ b/src/jit/jitconfig.cpp @@ -0,0 +1,344 @@ +// 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. + +#include "jitpch.h" +#ifdef _MSC_VER +#pragma hdrstop +#endif + +#include "jitconfig.h" + +JitConfigValues JitConfig; + +void JitConfigValues::MethodSet::initialize(const wchar_t* list, ICorJitHost* host) +{ + assert(m_list == nullptr); + + enum State + { + NO_NAME, + CLS_NAME, + FUNC_NAME, + ARG_LIST + }; // parsing state machine + + const char SEP_CHAR = ' '; // current character use to separate each entry + + wchar_t lastChar = '?'; // dummy + int nameStart = -1; // Index of the start of the current class or method name + MethodName currentName; // Buffer used while parsing the current entry + MethodName** lastName = &m_names; // Last entry inserted into the list + bool isQuoted = false; + + currentName.m_next = nullptr; + currentName.m_methodNameStart = -1; + currentName.m_methodNameLen = -1; + currentName.m_classNameStart = -1; + currentName.m_classNameLen = -1; + currentName.m_numArgs = -1; + + // Convert the input list to UTF-8 + int utf8ListLen = WszWideCharToMultiByte(CP_UTF8, 0, list, -1, nullptr, 0, nullptr, nullptr); + m_list = (char*)host->allocateMemory(utf8ListLen); + if (WszWideCharToMultiByte(CP_UTF8, 0, list, -1, const_cast<LPSTR>(m_list), utf8ListLen, nullptr, nullptr) == 0) + { + // Failed to convert the list. Free the memory and ignore the list. + host->freeMemory(reinterpret_cast<void*>(const_cast<char*>(m_list))); + m_list = ""; + return; + } + + State state = NO_NAME; + for (int i = 0; lastChar != '\0'; i++) + { + lastChar = m_list[i]; + + switch (state) + { + case NO_NAME: + if (m_list[i] != SEP_CHAR) + { + nameStart = i; + state = CLS_NAME; // we have found the start of the next entry + } + break; + + case CLS_NAME: + if (m_list[nameStart] == '"') + { + for (; m_list[i] != '\0' && m_list[i] != '"'; i++) + { + ; + } + + nameStart++; + isQuoted = true; + } + + if (m_list[i] == ':') + { + if (m_list[nameStart] == '*' && !isQuoted) + { + // The class name is a wildcard; mark it invalid. + currentName.m_classNameStart = -1; + currentName.m_classNameLen = -1; + } + else + { + currentName.m_classNameStart = nameStart; + currentName.m_classNameLen = i - nameStart; + + // Remove the trailing quote, if any + if (isQuoted) + { + currentName.m_classNameLen--; + isQuoted = false; + } + } + + // Accept class::name syntax as well + if (m_list[i + 1] == ':') + { + i++; + } + + nameStart = i + 1; + state = FUNC_NAME; + } + else if (m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == '(') + { + // Treat this as a method name without a class name. + currentName.m_classNameStart = -1; + currentName.m_classNameLen = -1; + goto DONE_FUNC_NAME; + } + break; + + case FUNC_NAME: + if (m_list[nameStart] == '"') + { + // The first half of the outer contdition handles the case where the + // class name is valid. + for (; nameStart == i || (m_list[i] != '\0' && m_list[i] != '"'); i++) + { + ; + } + + nameStart++; + isQuoted = true; + } + + if (m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == '(') + { + DONE_FUNC_NAME: + assert(m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == '('); + + if (m_list[nameStart] == '*' && !isQuoted) + { + // The method name is a wildcard; mark it invalid. + currentName.m_methodNameStart = -1; + currentName.m_methodNameLen = -1; + } + else + { + currentName.m_methodNameStart = nameStart; + currentName.m_methodNameLen = i - nameStart; + + // Remove the trailing quote, if any + if (isQuoted) + { + currentName.m_classNameLen--; + isQuoted = false; + } + } + + if (m_list[i] == '\0' || m_list[i] == SEP_CHAR) + { + currentName.m_numArgs = -1; + goto DONE_ARG_LIST; + } + else + { + assert(m_list[i] == '('); + currentName.m_numArgs = -1; + state = ARG_LIST; + } + } + break; + + case ARG_LIST: + if (m_list[i] == '\0' || m_list[i] == ')') + { + if (currentName.m_numArgs == -1) + { + currentName.m_numArgs = 0; + } + + DONE_ARG_LIST: + assert(m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == ')'); + + // We have parsed an entire method name; create a new entry in the list for it. + MethodName* name = (MethodName*)host->allocateMemory(sizeof(MethodName)); + *name = currentName; + + assert(name->m_next == nullptr); + *lastName = name; + lastName = &name->m_next; + + state = NO_NAME; + + // Skip anything after the argument list until we find the next + // separator character. Otherwise if we see "func(a,b):foo" we + // create entries for "func(a,b)" as well as ":foo". + if (m_list[i] == ')') + { + for (; m_list[i] && m_list[i] != SEP_CHAR; i++) + { + ; + } + + lastChar = m_list[i]; + } + } + else + { + if (m_list[i] != SEP_CHAR && currentName.m_numArgs == -1) + { + currentName.m_numArgs = 1; + } + + if (m_list[i] == ',') + { + currentName.m_numArgs++; + } + } + break; + + default: + assert(!"Bad state"); + break; + } + } +} + +void JitConfigValues::MethodSet::destroy(ICorJitHost* host) +{ + // Free method names, free the list string, and reset our state + for (MethodName *name = m_names, *next = nullptr; name != nullptr; name = next) + { + next = name->m_next; + host->freeMemory(reinterpret_cast<void*>(const_cast<MethodName*>(name))); + } + + host->freeMemory(reinterpret_cast<void*>(const_cast<char*>(m_list))); + + m_names = nullptr; + m_list = nullptr; +} + +static bool matchesName(const char* const name, int nameLen, const char* const s2) +{ + return strncmp(name, s2, nameLen) == 0 && s2[nameLen] == '\0'; +} + +bool JitConfigValues::MethodSet::contains(const char* methodName, + const char* className, + CORINFO_SIG_INFO* sigInfo) const +{ + int numArgs = sigInfo != nullptr ? sigInfo->numArgs : -1; + + // Try to match any the entries in the list. + for (MethodName* name = m_names; name != nullptr; name = name->m_next) + { + // If m_numArgs is valid, check for a mismatch + if (name->m_numArgs != -1 && name->m_numArgs != numArgs) + { + continue; + } + + // If m_methodNameStart is valid, check for a mismatch + if (name->m_methodNameStart != -1) + { + const char* expectedMethodName = &m_list[name->m_methodNameStart]; + if (!matchesName(expectedMethodName, name->m_methodNameLen, methodName)) + { + // C++ embeds the class name into the method name; deal with that here. + const char* colon = strchr(methodName, ':'); + if (colon != nullptr && colon[1] == ':' && + matchesName(expectedMethodName, name->m_methodNameLen, methodName)) + { + int classLen = (int)(colon - methodName); + if (name->m_classNameStart == -1 || + (classLen == name->m_classNameLen && + strncmp(&m_list[name->m_classNameStart], methodName, classLen) == 0)) + { + return true; + } + } + continue; + } + } + + // If m_classNameStart is valid, check for a mismatch + if (className == nullptr || name->m_classNameStart == -1 || + matchesName(&m_list[name->m_classNameStart], name->m_classNameLen, className)) + { + return true; + } + + // Check for suffix wildcard like System.* + if (name->m_classNameLen > 0 && m_list[name->m_classNameStart + name->m_classNameLen - 1] == '*' && + strncmp(&m_list[name->m_classNameStart], className, name->m_classNameLen - 1) == 0) + { + return true; + } + +#ifdef _DEBUG + // Maybe className doesn't include the namespace. Try to match that + const char* nsSep = strrchr(className, '.'); + if (nsSep != nullptr && nsSep != className) + { + const char* onlyClass = nsSep[-1] == '.' ? nsSep : &nsSep[1]; + if (matchesName(&m_list[name->m_classNameStart], name->m_classNameLen, onlyClass)) + { + return true; + } + } +#endif + } + + return false; +} + +void JitConfigValues::initialize(ICorJitHost* host) +{ + assert(!m_isInitialized); + +#define CONFIG_INTEGER(name, key, defaultValue) m_##name = host->getIntConfigValue(key, defaultValue); +#define CONFIG_STRING(name, key) m_##name = host->getStringConfigValue(key); +#define CONFIG_METHODSET(name, key) \ + const wchar_t* name##value = host->getStringConfigValue(key); \ + m_##name.initialize(name##value, host); \ + host->freeStringConfigValue(name##value); + +#include "jitconfigvalues.h" + + m_isInitialized = true; +} + +void JitConfigValues::destroy(ICorJitHost* host) +{ + if (!m_isInitialized) + { + return; + } + +#define CONFIG_INTEGER(name, key, defaultValue) +#define CONFIG_STRING(name, key) host->freeStringConfigValue(m_##name); +#define CONFIG_METHODSET(name, key) m_##name.destroy(host); + +#include "jitconfigvalues.h" + + m_isInitialized = false; +} |