Skip to content

Commit 93318a8

Browse files
authored
[lld-macho] Add swift support to ObjC category merger (llvm#95124)
Currently ObjC category merger only supports categories defined in ObjC. But swift supports generating ObjC categories also. This change adds supports for the later categories.
1 parent cc2dc09 commit 93318a8

File tree

3 files changed

+103
-9
lines changed

3 files changed

+103
-9
lines changed

lld/MachO/ObjC.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -675,15 +675,18 @@ void ObjcCategoryMerger::parseProtocolListInfo(const ConcatInputSection *isec,
675675
ptrList.structCount += protocolCount;
676676
ptrList.structSize = target->wordSize;
677677

678-
uint32_t expectedListSize =
678+
[[maybe_unused]] uint32_t expectedListSize =
679679
(protocolCount * target->wordSize) +
680680
/*header(count)*/ protocolListHeaderLayout.totalSize +
681681
/*extra null value*/ target->wordSize;
682-
assert(expectedListSize == ptrListSym->isec()->data.size() &&
683-
"Protocol list does not match expected size");
684682

685-
// Suppress unsuded var warning
686-
(void)expectedListSize;
683+
// On Swift, the protocol list does not have the extra (unnecessary) null
684+
[[maybe_unused]] uint32_t expectedListSizeSwift =
685+
expectedListSize - target->wordSize;
686+
687+
assert((expectedListSize == ptrListSym->isec()->data.size() ||
688+
expectedListSizeSwift == ptrListSym->isec()->data.size()) &&
689+
"Protocol list does not match expected size");
687690

688691
uint32_t off = protocolListHeaderLayout.totalSize;
689692
for (uint32_t inx = 0; inx < protocolCount; ++inx) {
@@ -1148,10 +1151,9 @@ void ObjcCategoryMerger::collectAndValidateCategoriesData() {
11481151
if (nlCategories.count(categorySym))
11491152
continue;
11501153

1151-
// We only support ObjC categories (no swift + @objc)
1152-
// TODO: Support swift + @objc categories also
1153-
if (!categorySym->getName().starts_with(objc::symbol_names::category))
1154-
continue;
1154+
assert(categorySym->getName().starts_with(objc::symbol_names::category) ||
1155+
categorySym->getName().starts_with(
1156+
objc::symbol_names::swift_objc_category));
11551157

11561158
auto *catBodyIsec = dyn_cast<ConcatInputSection>(categorySym->isec());
11571159
assert(catBodyIsec &&

lld/MachO/ObjC.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ constexpr const char categoryInstanceMethods[] =
3232
constexpr const char categoryClassMethods[] =
3333
"__OBJC_$_CATEGORY_CLASS_METHODS_";
3434
constexpr const char categoryProtocols[] = "__OBJC_CATEGORY_PROTOCOLS_$_";
35+
36+
constexpr const char swift_objc_category[] = "__CATEGORY_";
3537
} // namespace symbol_names
3638

3739
// Check for duplicate method names within related categories / classes.

lld/test/MachO/objc-category-merging-minimal.s

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
# RUN: llvm-objdump --objc-meta-data --macho merge_base_class_minimal_no_merge.dylib | FileCheck %s --check-prefixes=NO_MERGE_INTO_BASE
2424
# RUN: llvm-objdump --objc-meta-data --macho merge_base_class_minimal_yes_merge.dylib | FileCheck %s --check-prefixes=YES_MERGE_INTO_BASE
2525

26+
############ Test merging swift category into the base class ############
27+
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o MyBaseClassSwiftExtension.o MyBaseClassSwiftExtension.s
28+
# RUN: %lld -arch arm64 -dylib -o merge_base_class_swift_minimal_yes_merge.dylib -objc_category_merging MyBaseClassSwiftExtension.o merge_base_class_minimal.o
29+
# RUN: llvm-objdump --objc-meta-data --macho merge_base_class_swift_minimal_yes_merge.dylib | FileCheck %s --check-prefixes=YES_MERGE_INTO_BASE_SWIFT
2630

2731
#### Check merge categories enabled ###
2832
# Check that the original categories are not there
@@ -77,6 +81,21 @@ YES_MERGE_INTO_BASE-NEXT: name {{.*}} baseInstanceMethod
7781
YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8
7882
YES_MERGE_INTO_BASE-NEXT: imp -[MyBaseClass baseInstanceMethod]
7983

84+
85+
#### Check merge swift category into base class ###
86+
YES_MERGE_INTO_BASE_SWIFT: _OBJC_CLASS_$_MyBaseClass
87+
YES_MERGE_INTO_BASE_SWIFT-NEXT: _OBJC_METACLASS_$_MyBaseClass
88+
YES_MERGE_INTO_BASE_SWIFT: baseMethods
89+
YES_MERGE_INTO_BASE_SWIFT-NEXT: entsize 24
90+
YES_MERGE_INTO_BASE_SWIFT-NEXT: count 2
91+
YES_MERGE_INTO_BASE_SWIFT-NEXT: name {{.*}} swiftMethod
92+
YES_MERGE_INTO_BASE_SWIFT-NEXT: types {{.*}} v16@0:8
93+
YES_MERGE_INTO_BASE_SWIFT-NEXT: imp _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo
94+
YES_MERGE_INTO_BASE_SWIFT-NEXT: name {{.*}} baseInstanceMethod
95+
YES_MERGE_INTO_BASE_SWIFT-NEXT: types {{.*}} v16@0:8
96+
YES_MERGE_INTO_BASE_SWIFT-NEXT: imp -[MyBaseClass baseInstanceMethod]
97+
98+
8099
#--- a64_fakedylib.s
81100

82101
.section __DATA,__objc_data
@@ -279,3 +298,74 @@ L_OBJC_IMAGE_INFO:
279298
.long 0
280299
.long 64
281300
.subsections_via_symbols
301+
302+
303+
#--- MyBaseClassSwiftExtension.s
304+
; xcrun -sdk macosx swiftc -emit-assembly MyBaseClassSwiftExtension.swift -import-objc-header YourProject-Bridging-Header.h -o MyBaseClassSwiftExtension.s
305+
; ================== Generated from Swift: ==================
306+
; import Foundation
307+
; extension MyBaseClass {
308+
; @objc func swiftMethod() {
309+
; }
310+
; }
311+
; ================== Generated from Swift ===================
312+
.private_extern _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF
313+
.globl _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF
314+
.p2align 2
315+
_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF:
316+
.cfi_startproc
317+
mov w0, #0
318+
ret
319+
.cfi_endproc
320+
321+
.p2align 2
322+
_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo:
323+
.cfi_startproc
324+
mov w0, #0
325+
ret
326+
.cfi_endproc
327+
328+
.section __TEXT,__cstring,cstring_literals
329+
.p2align 4, 0x0
330+
l_.str.25.MyBaseClassSwiftExtension:
331+
.asciz "MyBaseClassSwiftExtension"
332+
333+
.section __TEXT,__objc_methname,cstring_literals
334+
"L_selector_data(swiftMethod)":
335+
.asciz "swiftMethod"
336+
337+
.section __TEXT,__cstring,cstring_literals
338+
"l_.str.7.v16@0:8":
339+
.asciz "v16@0:8"
340+
341+
.section __DATA,__objc_data
342+
.p2align 3, 0x0
343+
__CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyBaseClassSwiftExtension:
344+
.long 24
345+
.long 1
346+
.quad "L_selector_data(swiftMethod)"
347+
.quad "l_.str.7.v16@0:8"
348+
.quad _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo
349+
350+
.section __DATA,__objc_const
351+
.p2align 3, 0x0
352+
__CATEGORY_MyBaseClass_$_MyBaseClassSwiftExtension:
353+
.quad l_.str.25.MyBaseClassSwiftExtension
354+
.quad _OBJC_CLASS_$_MyBaseClass
355+
.quad __CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyBaseClassSwiftExtension
356+
.quad 0
357+
.quad 0
358+
.quad 0
359+
.quad 0
360+
.long 60
361+
.space 4
362+
363+
.section __DATA,__objc_catlist,regular,no_dead_strip
364+
.p2align 3, 0x0
365+
_objc_categories:
366+
.quad __CATEGORY_MyBaseClass_$_MyBaseClassSwiftExtension
367+
368+
.no_dead_strip _main
369+
.no_dead_strip l_entry_point
370+
371+
.subsections_via_symbols

0 commit comments

Comments
 (0)