[Debug] Add pointer based stringForPrintObject (#84742)

Adds an overload of `_DebuggerSupport.stringForPrintObject` which takes a pointer and mangled typename as arguments. This will be used to improve performance and resilience of `po` in lldb.

The pointer and mangled typename are used to construct an `Any` value, which is then passed into the primary implementation of `stringForPrintObject`.

This allows calling `stringForPrintObject` without having to first construct a context that contains all necessary Swift modules. This will improve speed, and also resilience when modules cannot be loaded for whatever reason.

rdar://158968103
This commit is contained in:
Dave Lee
2025-11-18 09:32:28 -08:00
committed by GitHub
parent b56f541732
commit b6b477de58
6 changed files with 99 additions and 0 deletions

View File

@@ -328,6 +328,38 @@ public enum _DebuggerSupport {
return target return target
} }
// Print an object or value without the caller having a concrete type.
//
// For simplicity of data handling in LLDB avoids using an enum return type,
// using (Bool, String) instead of Optional<String>.
@available(SwiftStdlib 6.3, *)
public static func stringForPrintObject(_ pointer: UnsafeRawPointer?, mangledTypeName: String) -> (Bool, String) {
guard let pointer = unsafe pointer else {
return (false, "invalid pointer")
}
guard let type =
unsafe _getTypeByMangledNameInContext(
mangledTypeName,
UInt(mangledTypeName.count),
genericContext: nil,
genericArguments: nil)
else {
return (false, "type not found for mangled name: \(mangledTypeName)")
}
func loadPointer<T>(type: T.Type) -> Any {
if type is AnyObject.Type {
unsafe unsafeBitCast(pointer, to: T.self)
} else {
unsafe pointer.load(as: T.self)
}
}
let anyValue = _openExistential(type, do: loadPointer)
return (true, stringForPrintObject(anyValue))
}
} }
public func _stringForPrintObject(_ value: Any) -> String { public func _stringForPrintObject(_ value: Any) -> String {

View File

@@ -6815,6 +6815,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
_$ss16TextOutputStreamPsE5_lockyyF _$ss16TextOutputStreamPsE5_lockyyF
_$ss16TextOutputStreamPsE7_unlockyyF _$ss16TextOutputStreamPsE7_unlockyyF
_$ss16TextOutputStreamTL _$ss16TextOutputStreamTL
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ _$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
_$ss16_DebuggerSupportOMa _$ss16_DebuggerSupportOMa
_$ss16_DebuggerSupportOMn _$ss16_DebuggerSupportOMn

View File

@@ -6815,6 +6815,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
_$ss16TextOutputStreamPsE5_lockyyF _$ss16TextOutputStreamPsE5_lockyyF
_$ss16TextOutputStreamPsE7_unlockyyF _$ss16TextOutputStreamPsE7_unlockyyF
_$ss16TextOutputStreamTL _$ss16TextOutputStreamTL
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ _$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
_$ss16_DebuggerSupportOMa _$ss16_DebuggerSupportOMa
_$ss16_DebuggerSupportOMn _$ss16_DebuggerSupportOMn

View File

@@ -6836,6 +6836,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
_$ss16TextOutputStreamPsE5_lockyyF _$ss16TextOutputStreamPsE5_lockyyF
_$ss16TextOutputStreamPsE7_unlockyyF _$ss16TextOutputStreamPsE7_unlockyyF
_$ss16TextOutputStreamTL _$ss16TextOutputStreamTL
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ _$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
_$ss16_DebuggerSupportOMa _$ss16_DebuggerSupportOMa
_$ss16_DebuggerSupportOMn _$ss16_DebuggerSupportOMn

View File

@@ -6836,6 +6836,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
_$ss16TextOutputStreamPsE5_lockyyF _$ss16TextOutputStreamPsE5_lockyyF
_$ss16TextOutputStreamPsE7_unlockyyF _$ss16TextOutputStreamPsE7_unlockyyF
_$ss16TextOutputStreamTL _$ss16TextOutputStreamTL
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ _$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
_$ss16_DebuggerSupportOMa _$ss16_DebuggerSupportOMa
_$ss16_DebuggerSupportOMn _$ss16_DebuggerSupportOMn

View File

@@ -10,6 +10,11 @@ struct StructWithMembers {
var b = "Hello World" var b = "Hello World"
} }
struct StructIsNonCopyable: ~Copyable {
var a = 1
var b = "Hello World"
}
class ClassWithMembers { class ClassWithMembers {
var a = 1 var a = 1
var b = "Hello World" var b = "Hello World"
@@ -108,6 +113,64 @@ if #available(SwiftStdlib 6.1, *) {
} }
} }
@available(SwiftStdlib 6.3, *)
func _expectStringForPrintObject<T>(_ pointer: UnsafePointer<T>, output: String) {
guard let mangledTypeName = _mangledTypeName(T.self) else {
expectTrue(false)
return
}
let (success, printed) =
_DebuggerSupport.stringForPrintObject(UnsafeRawPointer(pointer), mangledTypeName: mangledTypeName)
expectTrue(success)
expectEqual(printed, output)
}
if #available(SwiftStdlib 6.3, *) {
StringForPrintObjectTests.test("PointerWithMangledTypeName") {
var num = 33
_expectStringForPrintObject(&num, output: "33\n")
var val1 = StructWithMembers()
_expectStringForPrintObject(&val1, output: "▿ StructWithMembers\n - a : 1\n - b : \"Hello World\"\n")
var val2: StructWithMembers? = StructWithMembers()
_expectStringForPrintObject(&val2,
output: "▿ Optional<StructWithMembers>\n ▿ some : StructWithMembers\n - a : 1\n - b : \"Hello World\"\n")
do {
var val3 = StructIsNonCopyable()
if let mangledTypeName = _mangledTypeName(StructIsNonCopyable.self) {
withUnsafeBytes(of: &val3) { bytes in
guard let pointer = bytes.baseAddress else {
expectTrue(false)
return
}
let (success, printed) =
_DebuggerSupport.stringForPrintObject(pointer, mangledTypeName: mangledTypeName)
expectFalse(success)
expectEqual(printed, "type not found for mangled name: \(mangledTypeName)")
}
} else {
expectTrue(false)
}
}
do {
let obj = ClassWithMembers()
if let mangledTypeName = _mangledTypeName(ClassWithMembers.self) {
withExtendedLifetime(obj) { obj in
let pointer = unsafeBitCast(obj, to: UnsafeRawPointer.self)
let (success, printed) = _DebuggerSupport.stringForPrintObject(pointer, mangledTypeName: mangledTypeName)
expectTrue(success)
expectTrue(printed.hasPrefix("<ClassWithMembers: 0x"))
}
} else {
expectTrue(false)
}
}
}
}
class RefCountedObj { class RefCountedObj {
var patatino : Int var patatino : Int
init(_ p : Int) { init(_ p : Int) {