Skip to content

TypeSystemSwiftTypeRef: Make SwiftASTContext fallback switchable #10030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lldb/include/lldb/Core/ModuleList.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class ModuleListProperties : public Properties {
bool GetUseSwiftDWARFImporter() const;
bool SetUseSwiftDWARFImporter(bool new_value);
bool GetSwiftValidateTypeSystem() const;
bool GetSwiftTypeSystemFallback() const;
bool GetSwiftLoadConformances() const;
SwiftModuleLoadingMode GetSwiftModuleLoadingMode() const;
bool SetSwiftModuleLoadingMode(SwiftModuleLoadingMode);
Expand Down
1 change: 1 addition & 0 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ def setUpCommands(cls):
),
# Enable expensive validations in TypeSystemSwiftTypeRef.
"settings set symbols.swift-validate-typesystem true",
"settings set symbols.swift-typesystem-compiler-fallback true",
"settings set use-color false",
]

Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Core/CoreProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ let Definition = "modulelist" in {
def SwiftValidateTypeSystem: Property<"swift-validate-typesystem", "Boolean">,
DefaultFalse,
Desc<"Validate all Swift typesystem queries. Used for testing an asserts-enabled LLDB only.">;
def SwiftTypeSystemFallback
: Property<"swift-typesystem-compiler-fallback", "Boolean">,
DefaultTrue,
Desc<"If a query against reflection metadata / debug info fails, retry "
"using Swift modules.">;
def SwiftLoadConformances: Property<"swift-load-conformances", "Boolean">,
DefaultFalse,
Desc<"Resolve type alias via the conformance section. Disabled for performance reasons">;
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Core/ModuleList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ bool ModuleListProperties::GetSwiftValidateTypeSystem() const {
idx, g_modulelist_properties[idx].default_uint_value != 0);
}

bool ModuleListProperties::GetSwiftTypeSystemFallback() const {
const uint32_t idx = ePropertySwiftTypeSystemFallback;
return GetPropertyAtIndexAs<bool>(
idx, g_modulelist_properties[idx].default_uint_value != 0);
}

bool ModuleListProperties::GetSwiftLoadConformances() const {
const uint32_t idx = ePropertySwiftLoadConformances;
return GetPropertyAtIndexAs<bool>(
Expand Down
155 changes: 108 additions & 47 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2735,12 +2735,42 @@ constexpr ExecutionContextScope *g_no_exe_ctx = nullptr;
#define FORWARD_TO_EXPRAST_ONLY(FUNC, ARGS, DEFAULT_RETVAL) \
do { \
if (auto target_sp = GetTargetWP().lock()) \
if (auto swift_ast_ctx = GetSwiftASTContext( \
if (auto swift_ast_ctx = GetSwiftASTContext( \
SymbolContext(target_sp, target_sp->GetExecutableModule()))) \
return swift_ast_ctx->FUNC ARGS; \
return DEFAULT_RETVAL; \
} while (0)

bool TypeSystemSwiftTypeRef::UseSwiftASTContextFallback(
const char *func_name, lldb::opaque_compiler_type_t type) {
if (!ModuleList::GetGlobalModuleListProperties().GetSwiftTypeSystemFallback())
return false;

LLDB_LOGF(GetLog(LLDBLog::Types),
"TypeSystemSwiftTypeRef::%s(): Engaging SwiftASTContext fallback "
"for type %s",
func_name, AsMangledName(type));
return true;
}

bool TypeSystemSwiftTypeRef::DiagnoseSwiftASTContextFallback(
const char *func_name, lldb::opaque_compiler_type_t type) {
const char *type_name = AsMangledName(type);

std::optional<lldb::user_id_t> debugger_id;
if (auto target_sp = GetTargetWP().lock())
debugger_id = target_sp->GetDebugger().GetID();

std::string msg;
llvm::raw_string_ostream(msg)
<< "TypeSystemSwiftTypeRef::" << func_name
<< ": had to engage SwiftASTContext fallback for type " << type_name;
Debugger::ReportWarning(msg, debugger_id, &m_fallback_warning);

LLDB_LOGF(GetLog(LLDBLog::Types), "%s", msg.c_str());
return true;
}

CompilerType
TypeSystemSwiftTypeRef::RemangleAsType(swift::Demangle::Demangler &dem,
swift::Demangle::NodePointer node,
Expand Down Expand Up @@ -3453,14 +3483,16 @@ TypeSystemSwiftTypeRef::GetBitSize(opaque_compiler_type_t type,
if (auto result = runtime->GetBitSize({weak_from_this(), type}, exe_scope))
return result;
// Runtime failed, fallback to SwiftASTContext.
LLDB_LOGF(GetLog(LLDBLog::Types),
"Couldn't compute size of type %s using SwiftLanguageRuntime.",
AsMangledName(type));

if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope)))
return swift_ast_context->GetBitSize(ReconstructType(type, exe_scope),
exe_scope);
if (UseSwiftASTContextFallback(__FUNCTION__, type)) {
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope))) {
auto result = swift_ast_context->GetBitSize(
ReconstructType(type, exe_scope), exe_scope);
if (result)
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return result;
}
}
}

// FIXME: Move this to the top. Currently this causes VALIDATE
Expand Down Expand Up @@ -3501,12 +3533,16 @@ TypeSystemSwiftTypeRef::GetByteStride(opaque_compiler_type_t type,
return stride;
}
// Runtime failed, fallback to SwiftASTContext.
LLDB_LOGF(GetLog(LLDBLog::Types),
"Couldn't compute stride of type %s using SwiftLanguageRuntime.",
AsMangledName(type));
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope)))
return swift_ast_context->GetByteStride(ReconstructType(type), exe_scope);
if (UseSwiftASTContextFallback(__FUNCTION__, type)) {
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope))) {
auto result =
swift_ast_context->GetByteStride(ReconstructType(type), exe_scope);
if (result)
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return result;
}
}
return {};
};
VALIDATE_AND_RETURN(impl, GetByteStride, type, exe_scope,
Expand Down Expand Up @@ -3624,19 +3660,19 @@ TypeSystemSwiftTypeRef::GetNumChildren(opaque_compiler_type_t type,
impl, GetNumChildren, type, exe_ctx_obj,
(ReconstructType(type, exe_ctx), omit_empty_base_classes, exe_ctx));
}
LLDB_LOGF(GetLog(LLDBLog::Types),
"Using SwiftASTContext::GetNumChildren fallback for type %s",
AsMangledName(type));

// Try SwiftASTContext.
if (auto swift_ast_context = GetSwiftASTContext(GetSymbolContext(exe_ctx)))
if (auto n = llvm::expectedToStdOptional(swift_ast_context->GetNumChildren(
ReconstructType(type, exe_ctx), omit_empty_base_classes,
exe_ctx))) {
LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), num_children.takeError(),
"SwiftLanguageRuntime::GetNumChildren() failed: {0}");
return *n;
}
// Runtime failed, fallback to SwiftASTContext.
if (UseSwiftASTContextFallback(__FUNCTION__, type)) {
if (auto swift_ast_context = GetSwiftASTContext(GetSymbolContext(exe_ctx)))
if (auto n =
llvm::expectedToStdOptional(swift_ast_context->GetNumChildren(
ReconstructType(type, exe_ctx), omit_empty_base_classes,
exe_ctx))) {
LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), num_children.takeError(),
"SwiftLanguageRuntime::GetNumChildren() failed: {0}");
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return *n;
}
}

// Otherwise return the error from the runtime.
return num_children.takeError();
Expand Down Expand Up @@ -3686,12 +3722,16 @@ uint32_t TypeSystemSwiftTypeRef::GetNumFields(opaque_compiler_type_t type,
.value_or(0);
}

LLDB_LOGF(GetLog(LLDBLog::Types),
"Using SwiftASTContext::GetNumFields fallback for type %s",
AsMangledName(type));

if (auto swift_ast_context = GetSwiftASTContext(GetSymbolContext(exe_ctx)))
return swift_ast_context->GetNumFields(ReconstructType(type, exe_ctx), exe_ctx);
// Runtime failed, fallback to SwiftASTContext.
if (UseSwiftASTContextFallback(__FUNCTION__, type))
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_ctx))) {
auto result = swift_ast_context->GetNumFields(
ReconstructType(type, exe_ctx), exe_ctx);
if (result)
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return result;
}
return {};
}

Expand Down Expand Up @@ -3787,6 +3827,7 @@ TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
return ast_num_children.value_or(0);
};
auto impl = [&]() -> llvm::Expected<CompilerType> {
std::string error = "unknown error";
ExecutionContextScope *exe_scope = nullptr;
if (exe_ctx)
exe_scope = exe_ctx->GetBestExecutionContextScope();
Expand All @@ -3809,7 +3850,7 @@ TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
return result;
}
if (!result)
llvm::consumeError(result.takeError());
error = llvm::toString(result.takeError());
}
// Clang types can be resolved even without a process.
bool is_signed;
Expand Down Expand Up @@ -3923,10 +3964,17 @@ TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
"Couldn't compute size of type %s without a process.",
AsMangledName(type));

// FIXME: SwiftASTContext can sometimes find more Clang types because it
// imports Clang modules from source. We should be able to replicate this
// and remove this fallback.
return fallback();
// Runtime failed, fallback to SwiftASTContext.
if (UseSwiftASTContextFallback(__FUNCTION__, type)) {
// FIXME: SwiftASTContext can sometimes find more Clang types because it
// imports Clang modules from source. We should be able to replicate this
// and remove this fallback.
auto result = fallback();
if (result)
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return result;
}
return llvm::createStringError(llvm::inconvertibleErrorCode(), error);
};
// Skip validation when there is no process, because then we also
// don't have a runtime.
Expand Down Expand Up @@ -4080,10 +4128,17 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
"type %s",
AsMangledName(type));

if (auto swift_ast_context = GetSwiftASTContext(GetSymbolContext(exe_ctx)))
return swift_ast_context->GetIndexOfChildMemberWithName(
ReconstructType(type, exe_ctx), name, exe_ctx, omit_empty_base_classes,
child_indexes);
// Runtime failed, fallback to SwiftASTContext.
if (UseSwiftASTContextFallback(__FUNCTION__, type))
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_ctx))) {
auto result = swift_ast_context->GetIndexOfChildMemberWithName(
ReconstructType(type, exe_ctx), name, exe_ctx,
omit_empty_base_classes, child_indexes);
if (result)
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return result;
}
return {};
}

Expand Down Expand Up @@ -4388,10 +4443,16 @@ TypeSystemSwiftTypeRef::GetInstanceType(opaque_compiler_type_t type,
// type alias isn't possible, or the user might have defined the
// type alias in the REPL. In these cases, fallback to asking the AST
// for the canonical type.
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope)))
return swift_ast_context->GetInstanceType(
ReconstructType(type, exe_scope), exe_scope);
// Runtime failed, fallback to SwiftASTContext.
if (UseSwiftASTContextFallback(__FUNCTION__, type))
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope))) {
auto result = swift_ast_context->GetInstanceType(
ReconstructType(type, exe_scope), exe_scope);
if (result)
DiagnoseSwiftASTContextFallback(__FUNCTION__, type);
return result;
}
return {};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,13 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
GetManglingFlavor(ExecutionContext *exe_ctx = nullptr);

protected:
/// Determine whether the fallback is enabled via setting.
bool UseSwiftASTContextFallback(const char *func_name,
lldb::opaque_compiler_type_t type);
/// Print a warning that a fallback was necessary.
bool DiagnoseSwiftASTContextFallback(const char *func_name,
lldb::opaque_compiler_type_t type);

/// Helper that creates an AST type from \p type.
///
/// FIXME: This API is dangerous, it would be better to return a
Expand Down Expand Up @@ -555,6 +562,7 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
unsigned char retry_count = 0;
};

std::once_flag m_fallback_warning;
mutable std::mutex m_swift_ast_context_lock;
/// The "precise" SwiftASTContexts managed by this scratch context. There
/// exists one per Swift module. The keys in this map are module names.
Expand Down
6 changes: 4 additions & 2 deletions lldb/test/Shell/Swift/cond-breakpoint.test
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# REQUIRES: swift
# RUN: rm -rf %t && mkdir %t && cd %t
# RUN: %target-swiftc -g %S/Inputs/main.swift -o a.out
# RUN: %lldb a.out -b -s %s 2>&1 | FileCheck %s
# RUN: %target-swiftc -g %S/Inputs/main.swift -o %t/a.out
# RUN: %lldb %t/a.out -b -s %s 2>&1 | FileCheck %s

# CHECK-NOT: Stopped due to an error evaluating condition of breakpoint
# CHECK: stop reason = breakpoint

# The parentheses surrounding the expression matter.
br s -n main -c '((nil == nil))'
r
c
quit
1 change: 1 addition & 0 deletions lldb/test/Shell/lit-lldb-init.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ settings set target.auto-apply-fixits false
settings set target.inherit-tcc true
settings set target.detach-on-error false
settings set symbols.swift-validate-typesystem true
settings set symbols.swift-typesystem-compiler-fallback true