forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -491,7 +491,7 @@ class Dumper(DumperBase):
|
||||
raise Exception("cdb does not support calling functions")
|
||||
|
||||
def nameForCoreId(self, id):
|
||||
for dll in ['Utilsd4', 'Utils4']:
|
||||
for dll in ['Utilsd', 'Utils']:
|
||||
idName = cdbext.call('%s!Utils::nameForId(%d)' % (dll, id))
|
||||
if idName is not None:
|
||||
break
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user