Skip to content

Commit b6b477d

Browse files
authored
[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
1 parent b56f541 commit b6b477d

File tree

6 files changed

+99
-0
lines changed

6 files changed

+99
-0
lines changed

stdlib/public/core/DebuggerSupport.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,38 @@ public enum _DebuggerSupport {
328328

329329
return target
330330
}
331+
332+
// Print an object or value without the caller having a concrete type.
333+
//
334+
// For simplicity of data handling in LLDB avoids using an enum return type,
335+
// using (Bool, String) instead of Optional<String>.
336+
@available(SwiftStdlib 6.3, *)
337+
public static func stringForPrintObject(_ pointer: UnsafeRawPointer?, mangledTypeName: String) -> (Bool, String) {
338+
guard let pointer = unsafe pointer else {
339+
return (false, "invalid pointer")
340+
}
341+
342+
guard let type =
343+
unsafe _getTypeByMangledNameInContext(
344+
mangledTypeName,
345+
UInt(mangledTypeName.count),
346+
genericContext: nil,
347+
genericArguments: nil)
348+
else {
349+
return (false, "type not found for mangled name: \(mangledTypeName)")
350+
}
351+
352+
func loadPointer<T>(type: T.Type) -> Any {
353+
if type is AnyObject.Type {
354+
unsafe unsafeBitCast(pointer, to: T.self)
355+
} else {
356+
unsafe pointer.load(as: T.self)
357+
}
358+
}
359+
360+
let anyValue = _openExistential(type, do: loadPointer)
361+
return (true, stringForPrintObject(anyValue))
362+
}
331363
}
332364

333365
public func _stringForPrintObject(_ value: Any) -> String {

test/abi/Inputs/macOS/arm64/stdlib/baseline

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6815,6 +6815,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
68156815
_$ss16TextOutputStreamPsE5_lockyyF
68166816
_$ss16TextOutputStreamPsE7_unlockyyF
68176817
_$ss16TextOutputStreamTL
6818+
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
68186819
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
68196820
_$ss16_DebuggerSupportOMa
68206821
_$ss16_DebuggerSupportOMn

test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6815,6 +6815,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
68156815
_$ss16TextOutputStreamPsE5_lockyyF
68166816
_$ss16TextOutputStreamPsE7_unlockyyF
68176817
_$ss16TextOutputStreamTL
6818+
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
68186819
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
68196820
_$ss16_DebuggerSupportOMa
68206821
_$ss16_DebuggerSupportOMn

test/abi/Inputs/macOS/x86_64/stdlib/baseline

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6836,6 +6836,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
68366836
_$ss16TextOutputStreamPsE5_lockyyF
68376837
_$ss16TextOutputStreamPsE7_unlockyyF
68386838
_$ss16TextOutputStreamTL
6839+
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
68396840
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
68406841
_$ss16_DebuggerSupportOMa
68416842
_$ss16_DebuggerSupportOMn

test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6836,6 +6836,7 @@ _$ss16TextOutputStreamPsE11_writeASCIIyySRys5UInt8VGF
68366836
_$ss16TextOutputStreamPsE5_lockyyF
68376837
_$ss16TextOutputStreamPsE7_unlockyyF
68386838
_$ss16TextOutputStreamTL
6839+
_$ss16_DebuggerSupportO20stringForPrintObject_15mangledTypeNameSb_SStSVSg_SStFZ
68396840
_$ss16_DebuggerSupportO20stringForPrintObjectySSypFZ
68406841
_$ss16_DebuggerSupportOMa
68416842
_$ss16_DebuggerSupportOMn

test/stdlib/DebuggerSupport.swift

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ struct StructWithMembers {
1010
var b = "Hello World"
1111
}
1212

13+
struct StructIsNonCopyable: ~Copyable {
14+
var a = 1
15+
var b = "Hello World"
16+
}
17+
1318
class ClassWithMembers {
1419
var a = 1
1520
var b = "Hello World"
@@ -108,6 +113,64 @@ if #available(SwiftStdlib 6.1, *) {
108113
}
109114
}
110115

116+
@available(SwiftStdlib 6.3, *)
117+
func _expectStringForPrintObject<T>(_ pointer: UnsafePointer<T>, output: String) {
118+
guard let mangledTypeName = _mangledTypeName(T.self) else {
119+
expectTrue(false)
120+
return
121+
}
122+
let (success, printed) =
123+
_DebuggerSupport.stringForPrintObject(UnsafeRawPointer(pointer), mangledTypeName: mangledTypeName)
124+
expectTrue(success)
125+
expectEqual(printed, output)
126+
}
127+
128+
if #available(SwiftStdlib 6.3, *) {
129+
StringForPrintObjectTests.test("PointerWithMangledTypeName") {
130+
var num = 33
131+
_expectStringForPrintObject(&num, output: "33\n")
132+
133+
var val1 = StructWithMembers()
134+
_expectStringForPrintObject(&val1, output: "▿ StructWithMembers\n - a : 1\n - b : \"Hello World\"\n")
135+
136+
var val2: StructWithMembers? = StructWithMembers()
137+
_expectStringForPrintObject(&val2,
138+
output: "▿ Optional<StructWithMembers>\n ▿ some : StructWithMembers\n - a : 1\n - b : \"Hello World\"\n")
139+
140+
do {
141+
var val3 = StructIsNonCopyable()
142+
if let mangledTypeName = _mangledTypeName(StructIsNonCopyable.self) {
143+
withUnsafeBytes(of: &val3) { bytes in
144+
guard let pointer = bytes.baseAddress else {
145+
expectTrue(false)
146+
return
147+
}
148+
let (success, printed) =
149+
_DebuggerSupport.stringForPrintObject(pointer, mangledTypeName: mangledTypeName)
150+
expectFalse(success)
151+
expectEqual(printed, "type not found for mangled name: \(mangledTypeName)")
152+
}
153+
} else {
154+
expectTrue(false)
155+
}
156+
}
157+
158+
do {
159+
let obj = ClassWithMembers()
160+
if let mangledTypeName = _mangledTypeName(ClassWithMembers.self) {
161+
withExtendedLifetime(obj) { obj in
162+
let pointer = unsafeBitCast(obj, to: UnsafeRawPointer.self)
163+
let (success, printed) = _DebuggerSupport.stringForPrintObject(pointer, mangledTypeName: mangledTypeName)
164+
expectTrue(success)
165+
expectTrue(printed.hasPrefix("<ClassWithMembers: 0x"))
166+
}
167+
} else {
168+
expectTrue(false)
169+
}
170+
}
171+
}
172+
}
173+
111174
class RefCountedObj {
112175
var patatino : Int
113176
init(_ p : Int) {

0 commit comments

Comments
 (0)