Skip to content

Invalidate the reflection metadata cache when new symbols are added. #8181

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 1 commit into from
Feb 13, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ class SwiftLanguageRuntimeStub {
return {};
}

void SymbolsDidLoad(const ModuleList &module_list) {}
void ModulesDidLoad(const ModuleList &module_list) {}

bool IsStoredInlineInBuffer(CompilerType type) {
Expand Down Expand Up @@ -2359,6 +2360,10 @@ SwiftLanguageRuntime::GetReflectionContext() {
return m_stub->GetReflectionContext();
}

void SwiftLanguageRuntime::SymbolsDidLoad(const ModuleList &module_list) {
FORWARD(SymbolsDidLoad, module_list);
}

bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class SwiftLanguageRuntime : public LanguageRuntime {
return lldb::eLanguageTypeSwift;
}

void SymbolsDidLoad(const ModuleList &module_list) override;
void ModulesDidLoad(const ModuleList &module_list) override;

bool IsSymbolARuntimeThunk(const Symbol &symbol) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,27 +258,44 @@ void SwiftLanguageRuntimeImpl::PopLocalBuffer() {

class LLDBTypeInfoProvider : public swift::remote::TypeInfoProvider {
SwiftLanguageRuntimeImpl &m_runtime;
TypeSystemSwift &m_typesystem;
Status m_error;
llvm::Optional<SwiftScratchContextReader> m_reader;

public:
LLDBTypeInfoProvider(SwiftLanguageRuntimeImpl &runtime,
TypeSystemSwift &typesystem)
ExecutionContextScope *exe_scope)
: m_runtime(runtime),
// Always use the typeref type system so we have fewer cache
// invalidations.
m_typesystem(typesystem.GetTypeSystemSwiftTypeRef()) {}
m_reader(m_runtime.GetProcess().GetTarget().GetSwiftScratchContext(
m_error,
exe_scope ? *exe_scope : m_runtime.GetProcess().GetTarget())) {}
LLDBTypeInfoProvider(SwiftLanguageRuntimeImpl &runtime,
ExecutionContext *exe_ctx)
: m_runtime(runtime),
m_reader(m_runtime.GetProcess().GetTarget().GetSwiftScratchContext(
m_error, exe_ctx ? *exe_ctx->GetBestExecutionContextScope()
: m_runtime.GetProcess().GetTarget())) {}

swift::remote::TypeInfoProvider::IdType getId() override {
return (void *)&m_typesystem;
if (m_reader)
return (void *)((char *)m_reader->get() +
m_reader->get()->GetGeneration() +
m_runtime.GetGeneration());
return (void *)0;
}

const swift::reflection::TypeInfo *
getTypeInfo(llvm::StringRef mangledName) override {
// TODO: Should we cache the mangled name -> compiler type lookup, too?
Log *log(GetLog(LLDBLog::Types));
if (log)
LLDB_LOG(log, "[LLDBTypeInfoProvider] Looking up debug type info for {0}",
mangledName);
LLDB_LOG(GetLog(LLDBLog::Types),
"[LLDBTypeInfoProvider] Looking up debug type info for {0}",
mangledName);

if (!m_reader) {
LLDB_LOG(GetLog(LLDBLog::Types),
"[LLDBTypeInfoProvider] no scratch context");
return nullptr;
}
TypeSystemSwiftTypeRef &typesystem = *m_reader->get();

// Materialize a Clang type from the debug info.
assert(swift::Demangle::getManglingPrefixLength(mangledName) == 0);
Expand All @@ -303,18 +320,18 @@ class LLDBTypeInfoProvider : public swift::remote::TypeInfoProvider {
}
#endif
ConstString mangled(wrapped);
CompilerType swift_type = m_typesystem.GetTypeFromMangledTypename(mangled);
CompilerType swift_type = typesystem.GetTypeFromMangledTypename(mangled);
auto ts = swift_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
if (!ts)
return nullptr;
CompilerType clang_type;
bool is_imported =
ts->IsImportedType(swift_type.GetOpaqueQualType(), &clang_type);
if (!is_imported || !clang_type) {
if (log)
LLDB_LOG(log,
"[LLDBTypeInfoProvider] Could not find clang debug type info for {0}",
mangledName);
LLDB_LOG(GetLog(LLDBLog::Types),
"[LLDBTypeInfoProvider] Could not find clang debug type info "
"for {0}",
mangledName);
return nullptr;
}

Expand Down Expand Up @@ -344,10 +361,9 @@ class LLDBTypeInfoProvider : public swift::remote::TypeInfoProvider {
CompilerType field_type = clang_type.GetFieldAtIndex(
i, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
if (is_bitfield_ptr) {
Log *log(GetLog(LLDBLog::Types));
if (log)
log->Printf("[LLDBTypeInfoProvider] bitfield support is not yet "
"implemented");
LLDB_LOG(
GetLog(LLDBLog::Types),
"[LLDBTypeInfoProvider] bitfield support is not yet implemented");
continue;
}
swift::reflection::FieldInfo field_info = {
Expand Down Expand Up @@ -724,7 +740,7 @@ SwiftLanguageRuntimeImpl::GetNumChildren(CompilerType type,
if (!reflection_ctx)
return {};

LLDBTypeInfoProvider tip(*this, *ts);
LLDBTypeInfoProvider tip(*this, exe_scope);
auto *cti = reflection_ctx->GetClassInstanceTypeInfo(
tr, &tip, ts->GetDescriptorFinder());
if (auto *rti =
Expand Down Expand Up @@ -801,7 +817,7 @@ SwiftLanguageRuntimeImpl::GetNumFields(CompilerType type,
if (!reflection_ctx)
return {};

LLDBTypeInfoProvider tip(*this, *ts);
LLDBTypeInfoProvider tip(*this, exe_ctx);
auto *cti = reflection_ctx->GetClassInstanceTypeInfo(
tr, &tip, ts->GetDescriptorFinder());
if (auto *rti = llvm::dyn_cast_or_null<RecordTypeInfo>(cti)) {
Expand Down Expand Up @@ -964,7 +980,7 @@ SwiftLanguageRuntimeImpl::GetIndexOfChildMemberWithName(
++idx;
}

LLDBTypeInfoProvider tip(*this, *ts);
LLDBTypeInfoProvider tip(*this, exe_ctx);
// `current_tr` iterates the class hierarchy, from the current class, each
// superclass, and ends on null.
auto *current_tr = tr;
Expand Down Expand Up @@ -1083,7 +1099,7 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
if (!reflection_ctx)
return {};
// The indirect enum field should point to a closure context.
LLDBTypeInfoProvider tip(*this, *ts);
LLDBTypeInfoProvider tip(*this, &exe_ctx);
lldb::addr_t instance = MaskMaybeBridgedPointer(m_process, pointer);
auto *ti = reflection_ctx->GetTypeInfoFromInstance(
instance, &tip, ts->GetDescriptorFinder());
Expand Down Expand Up @@ -1261,7 +1277,7 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
return supers.size() >= 2;
};

LLDBTypeInfoProvider tip(*this, *instance_ts);
LLDBTypeInfoProvider tip(*this, &exe_ctx);
// Try out the instance pointer based super class traversal first, as its
// usually faster.
reflection_ctx->ForEachSuperClassType(&tip, ts->GetDescriptorFinder(),
Expand Down Expand Up @@ -1359,7 +1375,8 @@ bool SwiftLanguageRuntimeImpl::ForEachSuperClassType(
if (!ts)
return false;

LLDBTypeInfoProvider tip(*this, *ts);
ExecutionContext exe_ctx(instance.GetExecutionContextRef());
LLDBTypeInfoProvider tip(*this, &exe_ctx);
lldb::addr_t pointer = instance.GetPointerValue();
return reflection_ctx->ForEachSuperClassType(
&tip, ts->GetTypeSystemSwiftTypeRef().GetDescriptorFinder(),
Expand Down Expand Up @@ -2915,7 +2932,7 @@ SwiftLanguageRuntimeImpl::GetSwiftRuntimeTypeInfo(
if (!reflection_ctx)
return nullptr;

LLDBTypeInfoProvider provider(*this, *ts);
LLDBTypeInfoProvider provider(*this, exe_scope);
return reflection_ctx->GetTypeInfo(
type_ref, &provider,
ts->GetTypeSystemSwiftTypeRef().GetDescriptorFinder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class SwiftLanguageRuntimeImpl {
std::unordered_map<std::string, std::vector<std::string>> m_enum_spec;
};

unsigned GetGeneration() const { return m_generation; }
void SymbolsDidLoad(const ModuleList &module_list) { ++m_generation; }
void ModulesDidLoad(const ModuleList &module_list);

bool GetObjectDescription(Stream &str, ValueObject &object);
Expand Down Expand Up @@ -403,6 +405,8 @@ class SwiftLanguageRuntimeImpl {
/// added to the reflection context once it's being initialized.
ModuleList m_modules_to_add;

/// Increased every time SymbolsDidLoad is called.
unsigned m_generation = 0;
/// Add the image to the reflection context.
/// \return true on success.
bool AddModuleToReflectionContext(const lldb::ModuleSP &module_sp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ IsClangImportedType(NodePointer node,
case Node::Kind::Enum:
case Node::Kind::TypeAlias:
if (!IsClangImportedType(node->getFirstChild(), decl_context))
return false;
return false;

// When C++ interop is enabled, Swift enums represent Swift namespaces.
decl_context.push_back({node->getKind() == Node::Kind::Enum
Expand Down Expand Up @@ -1489,6 +1489,7 @@ void TypeSystemSwiftTypeRef::NotifyAllTypeSystems(

void TypeSystemSwiftTypeRefForExpressions::ModulesDidLoad(
ModuleList &module_list) {
++m_generation;
NotifyAllTypeSystems([&](TypeSystemSP ts_sp) {
if (auto swift_ast_ctx =
llvm::dyn_cast_or_null<SwiftASTContextForExpressions>(ts_sp.get()))
Expand Down Expand Up @@ -3163,9 +3164,9 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
child_is_deref_of_parent = false;
language_flags = 0;
auto fallback = [&]() -> CompilerType {
LLDB_LOGF(GetLog(LLDBLog::Types),
"Had to engage SwiftASTContext fallback for type %s.",
AsMangledName(type));
LLDB_LOG(GetLog(LLDBLog::Types),
"Had to engage SwiftASTContext fallback for type {0}, field #{1}.",
AsMangledName(type), idx);
if (auto *swift_ast_context =
GetSwiftASTContextFromExecutionContext(exe_ctx))
return swift_ast_context->GetChildCompilerTypeAtIndex(
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,13 @@ class TypeSystemSwiftTypeRefForExpressions : public TypeSystemSwiftTypeRef {
/// Forwards to SwiftASTContext.
PersistentExpressionState *GetPersistentExpressionState() override;
Status PerformCompileUnitImports(const SymbolContext &sc);
/// Returns how often ModulesDidLoad was called/
unsigned GetGeneration() const { return m_generation; }

friend class SwiftASTContextForExpressions;
protected:
lldb::TargetWP m_target_wp;
unsigned m_generation = 0;

/// This exists to implement the PerformCompileUnitImports
/// mechanism.
Expand Down
6 changes: 6 additions & 0 deletions lldb/test/API/lang/swift/late_symbols/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SWIFT_SOURCES := main.swift
SWIFT_BRIDGING_HEADER := bridging.h
DISABLE_SWIFT_INTERFACE := YES
HIDE_SWIFTMODULE := YES

include Makefile.rules
47 changes: 47 additions & 0 deletions lldb/test/API/lang/swift/late_symbols/TestSwiftLateSymbols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
import unittest2
import shutil
import os

class TestSwiftLateSymbols(TestBase):
@swiftTest
@skipUnlessDarwin
@skipIf(debug_info=no_match(["dsym"]))
def test_any_object_type(self):
"""Test the AnyObject type"""
self.build()
dsym = self.getBuildArtifact('a.out.dSYM')
stash = self.getBuildArtifact('hidden.noindex')
os.unlink(self.getBuildArtifact('main.swift.o'))
os.makedirs(stash)
shutil.move(dsym, stash)
target, process, thread, bkpt = lldbutil.run_to_name_breakpoint(
self, 'breakpoint')
# return to main(), at a place where all variables are available
thread.StepOut()

frame = thread.frames[0]
var_object = frame.FindVariable("object", lldb.eNoDynamicValues)
self.assertFalse(var_object.IsValid())

self.expect('add-dsym ' + stash + '/a.out.dSYM')
frame = thread.frames[0]
var_object = frame.FindVariable("object", lldb.eNoDynamicValues)
self.assertTrue(var_object.IsValid())

lldbutil.check_variable(
self,
var_object,
use_dynamic=False,
typename="bridging.h.FromC")
var_object_x = var_object.GetDynamicValue(
lldb.eDynamicCanRunTarget).GetChildMemberWithName("i")
lldbutil.check_variable(
self,
var_object_x,
use_dynamic=False,
value='23',
typename="Swift.Int32")
3 changes: 3 additions & 0 deletions lldb/test/API/lang/swift/late_symbols/bridging.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
struct FromC {
int i;
};
11 changes: 11 additions & 0 deletions lldb/test/API/lang/swift/late_symbols/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
func use<T>(_ t: T) {}
func breakpoint(_ object: FromC) {
print("stop")
}

func main() {
var object = FromC(i: 23)
breakpoint(object)
}

main()