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.
10 #include "jitconfig.h"
12 JitConfigValues JitConfig;
14 void JitConfigValues::MethodSet::initialize(const wchar_t* list, ICorJitHost* host)
16 assert(m_list == nullptr);
17 assert(m_names == nullptr);
25 }; // parsing state machine
27 const char SEP_CHAR = ' '; // current character use to separate each entry
29 wchar_t lastChar = '?'; // dummy
30 int nameStart = -1; // Index of the start of the current class or method name
31 MethodName currentName; // Buffer used while parsing the current entry
32 MethodName** lastName = &m_names; // Last entry inserted into the list
33 bool isQuoted = false;
35 currentName.m_next = nullptr;
36 currentName.m_methodNameStart = -1;
37 currentName.m_methodNameLen = -1;
38 currentName.m_classNameStart = -1;
39 currentName.m_classNameLen = -1;
40 currentName.m_numArgs = -1;
42 // Convert the input list to UTF-8
43 int utf8ListLen = WszWideCharToMultiByte(CP_UTF8, 0, list, -1, nullptr, 0, nullptr, nullptr);
44 m_list = (char*)host->allocateMemory(utf8ListLen);
45 if (WszWideCharToMultiByte(CP_UTF8, 0, list, -1, const_cast<LPSTR>(m_list), utf8ListLen, nullptr, nullptr) == 0)
47 // Failed to convert the list. Free the memory and ignore the list.
48 host->freeMemory(reinterpret_cast<void*>(const_cast<char*>(m_list)));
53 State state = NO_NAME;
54 for (int i = 0; lastChar != '\0'; i++)
61 if (m_list[i] != SEP_CHAR)
64 state = CLS_NAME; // we have found the start of the next entry
69 if (m_list[nameStart] == '"')
71 for (; m_list[i] != '\0' && m_list[i] != '"'; i++)
82 if (m_list[nameStart] == '*' && !isQuoted)
84 // The class name is a wildcard; mark it invalid.
85 currentName.m_classNameStart = -1;
86 currentName.m_classNameLen = -1;
90 currentName.m_classNameStart = nameStart;
91 currentName.m_classNameLen = i - nameStart;
93 // Remove the trailing quote, if any
96 currentName.m_classNameLen--;
101 // Accept class::name syntax as well
102 if (m_list[i + 1] == ':')
110 else if (m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == '(')
112 // Treat this as a method name without a class name.
113 currentName.m_classNameStart = -1;
114 currentName.m_classNameLen = -1;
120 if (m_list[nameStart] == '"')
122 // The first half of the outer contdition handles the case where the
123 // class name is valid.
124 for (; nameStart == i || (m_list[i] != '\0' && m_list[i] != '"'); i++)
133 if (m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == '(')
136 assert(m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == '(');
138 if (m_list[nameStart] == '*' && !isQuoted)
140 // The method name is a wildcard; mark it invalid.
141 currentName.m_methodNameStart = -1;
142 currentName.m_methodNameLen = -1;
146 currentName.m_methodNameStart = nameStart;
147 currentName.m_methodNameLen = i - nameStart;
149 // Remove the trailing quote, if any
152 currentName.m_classNameLen--;
157 if (m_list[i] == '\0' || m_list[i] == SEP_CHAR)
159 currentName.m_numArgs = -1;
164 assert(m_list[i] == '(');
165 currentName.m_numArgs = -1;
172 if (m_list[i] == '\0' || m_list[i] == ')')
174 if (currentName.m_numArgs == -1)
176 currentName.m_numArgs = 0;
180 assert(m_list[i] == '\0' || m_list[i] == SEP_CHAR || m_list[i] == ')');
182 // We have parsed an entire method name; create a new entry in the list for it.
183 MethodName* name = (MethodName*)host->allocateMemory(sizeof(MethodName));
186 assert(name->m_next == nullptr);
188 lastName = &name->m_next;
192 // Skip anything after the argument list until we find the next
193 // separator character. Otherwise if we see "func(a,b):foo" we
194 // create entries for "func(a,b)" as well as ":foo".
195 if (m_list[i] == ')')
197 for (; m_list[i] && m_list[i] != SEP_CHAR; i++)
202 lastChar = m_list[i];
207 if (m_list[i] != SEP_CHAR && currentName.m_numArgs == -1)
209 currentName.m_numArgs = 1;
212 if (m_list[i] == ',')
214 currentName.m_numArgs++;
220 assert(!"Bad state");
226 void JitConfigValues::MethodSet::destroy(ICorJitHost* host)
228 // Free method names, free the list string, and reset our state
229 for (MethodName *name = m_names, *next = nullptr; name != nullptr; name = next)
232 host->freeMemory(reinterpret_cast<void*>(const_cast<MethodName*>(name)));
234 if (m_list != nullptr)
236 host->freeMemory(reinterpret_cast<void*>(const_cast<char*>(m_list)));
242 static bool matchesName(const char* const name, int nameLen, const char* const s2)
244 return strncmp(name, s2, nameLen) == 0 && s2[nameLen] == '\0';
247 bool JitConfigValues::MethodSet::contains(const char* methodName,
248 const char* className,
249 CORINFO_SIG_INFO* sigInfo) const
251 int numArgs = sigInfo != nullptr ? sigInfo->numArgs : -1;
253 // Try to match any the entries in the list.
254 for (MethodName* name = m_names; name != nullptr; name = name->m_next)
256 // If m_numArgs is valid, check for a mismatch
257 if (name->m_numArgs != -1 && name->m_numArgs != numArgs)
262 // If m_methodNameStart is valid, check for a mismatch
263 if (name->m_methodNameStart != -1)
265 const char* expectedMethodName = &m_list[name->m_methodNameStart];
266 if (!matchesName(expectedMethodName, name->m_methodNameLen, methodName))
268 // C++ embeds the class name into the method name; deal with that here.
269 const char* colon = strchr(methodName, ':');
270 if (colon != nullptr && colon[1] == ':' &&
271 matchesName(expectedMethodName, name->m_methodNameLen, methodName))
273 int classLen = (int)(colon - methodName);
274 if (name->m_classNameStart == -1 ||
275 (classLen == name->m_classNameLen &&
276 strncmp(&m_list[name->m_classNameStart], methodName, classLen) == 0))
285 // If m_classNameStart is valid, check for a mismatch
286 if (className == nullptr || name->m_classNameStart == -1 ||
287 matchesName(&m_list[name->m_classNameStart], name->m_classNameLen, className))
292 // Check for suffix wildcard like System.*
293 if (name->m_classNameLen > 0 && m_list[name->m_classNameStart + name->m_classNameLen - 1] == '*' &&
294 strncmp(&m_list[name->m_classNameStart], className, name->m_classNameLen - 1) == 0)
300 // Maybe className doesn't include the namespace. Try to match that
301 const char* nsSep = strrchr(className, '.');
302 if (nsSep != nullptr && nsSep != className)
304 const char* onlyClass = nsSep[-1] == '.' ? nsSep : &nsSep[1];
305 if (matchesName(&m_list[name->m_classNameStart], name->m_classNameLen, onlyClass))
316 void JitConfigValues::initialize(ICorJitHost* host)
318 assert(!m_isInitialized);
320 #define CONFIG_INTEGER(name, key, defaultValue) m_##name = host->getIntConfigValue(key, defaultValue);
321 #define CONFIG_STRING(name, key) m_##name = host->getStringConfigValue(key);
322 #define CONFIG_METHODSET(name, key) \
323 const wchar_t* name##value = host->getStringConfigValue(key); \
324 m_##name.initialize(name##value, host); \
325 host->freeStringConfigValue(name##value);
327 #include "jitconfigvalues.h"
329 m_isInitialized = true;
332 void JitConfigValues::destroy(ICorJitHost* host)
334 if (!m_isInitialized)
339 #define CONFIG_INTEGER(name, key, defaultValue)
340 #define CONFIG_STRING(name, key) host->freeStringConfigValue(m_##name);
341 #define CONFIG_METHODSET(name, key) m_##name.destroy(host);
343 #include "jitconfigvalues.h"
345 m_isInitialized = false;