aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/qtcreatorcdbext
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2023-02-10 10:20:10 +0100
committerDavid Schulz <david.schulz@qt.io>2023-02-14 13:21:38 +0000
commite47dae643ab3317fdb075496925bef6fea3f238f (patch)
tree8dd52f2b1ef2755f0836803711ead61d8f256435 /src/libs/qtcreatorcdbext
parent72de50df83855f3340f72c61847252807518da1f (diff)
Cdbext: lazy type lookup
Postpone the lookup until we need the type id. This potentially skips the lookup for unresolvable types that are just to parse template parameters. Also cache types we already checked to prevent looking up types multiple times. Additionally traverse all modules in order to find unresolvable types. This combination reduces the time the debugger needs to execute all dumper tests from ~7:30 to ~3:30 on my machine. Task-number: QTCREATORBUG-18287 Change-Id: Ie1e9771f124096c2a9ad24ac26c9b51fcded4fed Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/libs/qtcreatorcdbext')
-rw-r--r--src/libs/qtcreatorcdbext/pytype.cpp154
-rw-r--r--src/libs/qtcreatorcdbext/pytype.h16
2 files changed, 124 insertions, 46 deletions
diff --git a/src/libs/qtcreatorcdbext/pytype.cpp b/src/libs/qtcreatorcdbext/pytype.cpp
index b6844dcb62..a3c47aeba7 100644
--- a/src/libs/qtcreatorcdbext/pytype.cpp
+++ b/src/libs/qtcreatorcdbext/pytype.cpp
@@ -196,22 +196,49 @@ static std::string getModuleName(ULONG64 module)
return std::string();
}
+static std::unordered_map<std::string, PyType> &typeCache()
+{
+ static std::unordered_map<std::string, PyType> cache;
+ return cache;
+}
+
PyType::PyType(ULONG64 module, unsigned long typeId, const std::string &name, int tag)
- : m_module(module)
- , m_typeId(typeId)
+ : m_typeId(typeId)
+ , m_module(module)
, m_resolved(true)
, m_tag(tag)
{
- m_name = SymbolGroupValue::stripClassPrefixes(name);
- if (m_name.compare(0, 6, "union ") == 0)
- m_name.erase(0, 6);
- if (m_name == "<function> *")
- m_name.erase(10);
+ if (!name.empty()) {
+ m_name = SymbolGroupValue::stripClassPrefixes(name);
+ if (m_name.compare(0, 6, "union ") == 0)
+ m_name.erase(0, 6);
+ if (m_name == "<function> *")
+ m_name.erase(10);
+ typeCache()[m_name] = *this;
+ if (debuggingTypeEnabled())
+ DebugPrint() << "create resolved '" << m_name << "'";
+ }
+}
+
+PyType::PyType(const std::string &name, ULONG64 module)
+ : m_module(module)
+ , m_name(name)
+{
+ if (!m_name.empty()) {
+ m_name = SymbolGroupValue::stripClassPrefixes(name);
+ if (m_name.compare(0, 6, "union ") == 0)
+ m_name.erase(0, 6);
+ if (m_name == "<function> *")
+ m_name.erase(10);
+ }
+
+ if (debuggingTypeEnabled())
+ DebugPrint() << "create unresolved '" << m_name << "'";
}
std::string PyType::name(bool withModule) const
{
- if (m_name.empty()) {
+ if (m_name.empty() && m_resolved.value_or(false)) {
auto symbols = ExtensionCommandContext::instance()->symbols();
ULONG size = 0;
symbols->GetTypeName(m_module, m_typeId, NULL, 0, &size);
@@ -223,6 +250,7 @@ std::string PyType::name(bool withModule) const
return std::string();
m_name = typeName;
+ typeCache()[m_name] = *this;
}
if (withModule && !isIntegralType(m_name) && !isFloatType(m_name)) {
@@ -238,7 +266,7 @@ std::string PyType::name(bool withModule) const
ULONG64 PyType::bitsize() const
{
- if (!m_resolved)
+ if (!resolve())
return 0;
ULONG size = 0;
@@ -250,12 +278,7 @@ ULONG64 PyType::bitsize() const
int PyType::code() const
{
- if (!m_resolved)
- return TypeCodeUnresolvable;
-
- if (m_tag < 0) {
- // try to parse typeName
- const std::string &typeName = name();
+ auto parseTypeName = [this](const std::string &typeName) -> std::optional<TypeCodes> {
if (typeName.empty())
return TypeCodeUnresolvable;
if (isPointerType(typeName))
@@ -268,14 +291,22 @@ int PyType::code() const
return TypeCodeIntegral;
if (isFloatType(typeName))
return TypeCodeFloat;
+ if (knownType(name(), 0) != KT_Unknown)
+ return TypeCodeStruct;
+ return std::nullopt;
+ };
+
+ if (!resolve())
+ return parseTypeName(name()).value_or(TypeCodeUnresolvable);
+
+ if (m_tag < 0) {
+ if (const std::optional<TypeCodes> typeCode = parseTypeName(name()))
+ return *typeCode;
IDebugSymbolGroup2 *sg = 0;
if (FAILED(ExtensionCommandContext::instance()->symbols()->CreateSymbolGroup2(&sg)))
return TypeCodeStruct;
- if (knownType(name(), 0) != KT_Unknown)
- return TypeCodeStruct;
-
const std::string helperValueName = SymbolGroupValue::pointedToSymbolName(0, name(true));
ULONG index = DEBUG_ANY_ID;
if (SUCCEEDED(sg->AddSymbol(helperValueName.c_str(), &index)))
@@ -323,6 +354,9 @@ std::string PyType::targetName() const
PyFields PyType::fields() const
{
+ if (!resolve())
+ return {};
+
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
PyFields fields;
if (isArrayType(name()) || isPointerType(name()))
@@ -343,19 +377,25 @@ PyFields PyType::fields() const
std::string PyType::module() const
{
+ if (!resolve())
+ return {};
+
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
- ULONG size;
+ ULONG size = 0;
symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, DEBUG_ANY_ID, m_module, NULL, 0, &size);
+ if (size == 0)
+ return {};
std::string name(size - 1, '\0');
if (SUCCEEDED(symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, DEBUG_ANY_ID,
m_module, &name[0], size, NULL))) {
return name;
}
- return std::string();
+ return {};
}
ULONG64 PyType::moduleId() const
{
+ resolve();
return m_module;
}
@@ -408,37 +448,73 @@ PyType PyType::lookupType(const std::string &typeNameIn, ULONG64 module)
typeName.erase(0, 7);
const static std::regex typeNameRE("^[a-zA-Z_][a-zA-Z0-9_]*!?[a-zA-Z0-9_<>:, \\*\\&\\[\\]]*$");
- if (!std::regex_match(typeName, typeNameRE))
- return PyType();
-
- CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
- ULONG typeId;
- HRESULT result = S_FALSE;
- if (module != 0 && !isIntegralType(typeName) && !isFloatType(typeName))
- result = symbols->GetTypeId(module, typeName.c_str(), &typeId);
- if (FAILED(result) || result == S_FALSE)
- result = symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module);
- if (FAILED(result))
- return createUnresolvedType(typeName);
- return PyType(module, typeId, typeName);
-
+ if (std::regex_match(typeName, typeNameRE))
+ return PyType(typeName, module);
+ return PyType();
}
-PyType PyType::createUnresolvedType(const std::string &typeName)
+bool PyType::resolve() const
{
- PyType unresolvedType;
- unresolvedType.m_name = typeName;
- return unresolvedType;
+ if (m_resolved)
+ return *m_resolved;
+
+ if (!m_name.empty()) {
+ auto cacheIt = typeCache().find(m_name);
+ if (cacheIt != typeCache().end() && cacheIt->second.m_resolved.has_value()) {
+ if (debuggingTypeEnabled())
+ DebugPrint() << "found cached '" << m_name << "'";
+
+ // found a resolved cache entry use the ids of this entry
+ m_typeId = cacheIt->second.m_typeId;
+ m_module = cacheIt->second.m_module;
+ m_resolved = cacheIt->second.m_resolved;
+ } else {
+ if (debuggingTypeEnabled())
+ DebugPrint() << "resolve '" << m_name << "'";
+
+ CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
+ ULONG typeId;
+ HRESULT result = S_FALSE;
+ if (m_module != 0 && !isIntegralType(m_name) && !isFloatType(m_name))
+ result = symbols->GetTypeId(m_module, m_name.c_str(), &typeId);
+ if (FAILED(result) || result == S_FALSE) {
+ ULONG64 module;
+ if (isIntegralType(m_name))
+ result = symbols->GetSymbolTypeId(m_name.c_str(), &typeId, &module);
+ if (FAILED(result) || result == S_FALSE) {
+ ULONG loaded = 0;
+ ULONG unloaded = 0;
+ symbols->GetNumberModules(&loaded, &unloaded);
+ ULONG moduleCount = loaded + unloaded;
+ for (ULONG moduleIndex = 0;
+ (FAILED(result) || result == S_FALSE) && moduleIndex < moduleCount;
+ ++moduleIndex) {
+ symbols->GetModuleByIndex(moduleIndex, &module);
+ result = symbols->GetTypeId(module, m_name.c_str(), &typeId);
+ }
+ }
+
+ m_module = SUCCEEDED(result) ? module : 0;
+ }
+ m_typeId = SUCCEEDED(result) ? typeId : 0;
+ m_resolved = SUCCEEDED(result);
+ typeCache()[m_name] = *this;
+ }
+ }
+ if (!m_resolved)
+ m_resolved = false;
+ return *m_resolved;
}
unsigned long PyType::getTypeId() const
{
+ resolve();
return m_typeId;
}
bool PyType::isValid() const
{
- return m_resolved;
+ return !m_name.empty() || m_resolved.has_value();
}
// Python interface implementation
diff --git a/src/libs/qtcreatorcdbext/pytype.h b/src/libs/qtcreatorcdbext/pytype.h
index 968d59717c..8b05fffe0a 100644
--- a/src/libs/qtcreatorcdbext/pytype.h
+++ b/src/libs/qtcreatorcdbext/pytype.h
@@ -3,8 +3,9 @@
#pragma once
-#include <string>
#include <memory>
+#include <optional>
+#include <string>
#include <Python.h>
@@ -16,6 +17,7 @@ public:
PyType() = default;
PyType(ULONG64 module, unsigned long typeId,
const std::string &name = std::string(), int tag = -1);
+ explicit PyType(const std::string &name, ULONG64 module = 0);
PyType(const PyType &other) = default;
std::string name(bool withModule = false) const;
@@ -48,13 +50,13 @@ public:
static PyType lookupType(const std::string &typeName, ULONG64 module = 0);
private:
- static PyType createUnresolvedType(const std::string &typeName);
+ bool resolve() const;
- unsigned long m_typeId = 0;
- ULONG64 m_module = 0;
- bool m_resolved = false;
- mutable std::string m_name;
- mutable int m_tag = -1;
+ mutable unsigned long m_typeId = 0;
+ mutable ULONG64 m_module = 0;
+ mutable std::optional<bool> m_resolved;
+ mutable std::string m_name;
+ mutable int m_tag = -1;
};
struct TypePythonObject