Skip to content

[5.2] IRGen: don't create ObjC methods with the unnamed_addr attribute #29229

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
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
7 changes: 5 additions & 2 deletions lib/IRGen/GenObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -919,8 +919,11 @@ static llvm::Constant *findSwiftAsObjCThunk(IRGenModule &IGM, SILDeclRef ref,
assert(SILFn && "no IR function for swift-as-objc thunk");
auto fn = IGM.getAddrOfSILFunction(SILFn, NotForDefinition);
ApplyIRLinkage(IRLinkage::Internal).to(fn);
fn->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);

// Don't add the unnamed_addr attribute: in some places Foundation is
// comparing ObjC method pointers. Therefore LLVM's function merging pass must
// not create aliases for identical functions, but create thunks.
// This can be ensured if ObjC methods are not created with the unnamed_addr
// attribute.
return llvm::ConstantExpr::getBitCast(fn, IGM.Int8PtrTy);
}

Expand Down
70 changes: 35 additions & 35 deletions test/IRGen/abitypes.swift

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions test/IRGen/objc_bridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,57 +130,57 @@ var NSS : NSString = NSString()

// -- NSString methods don't convert 'self'
extension NSString {
// CHECK: define internal [[OPAQUE:.*]]* @"$sSo8NSStringC11objc_bridgeE13nsstrFakePropABvgTo"([[OPAQUE:.*]]*, i8*) unnamed_addr
// CHECK: define internal void @"$sSo8NSStringC11objc_bridgeE13nsstrFakePropABvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr
// CHECK: define internal [[OPAQUE:.*]]* @"$sSo8NSStringC11objc_bridgeE13nsstrFakePropABvgTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
// CHECK: define internal void @"$sSo8NSStringC11objc_bridgeE13nsstrFakePropABvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc var nsstrFakeProp : NSString {
get {
return NSS
}
set {}
}

// CHECK: define internal [[OPAQUE:.*]]* @"$sSo8NSStringC11objc_bridgeE11nsstrResultAByFTo"([[OPAQUE:.*]]*, i8*) unnamed_addr
// CHECK: define internal [[OPAQUE:.*]]* @"$sSo8NSStringC11objc_bridgeE11nsstrResultAByFTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
@objc func nsstrResult() -> NSString { return NSS }

// CHECK: define internal void @"$sSo8NSStringC11objc_bridgeE8nsstrArg1syAB_tFTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr
// CHECK: define internal void @"$sSo8NSStringC11objc_bridgeE8nsstrArg1syAB_tFTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc func nsstrArg(s s: NSString) { }
}

class Bas : NSObject {
// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC11strRealPropSSvgTo"([[OPAQUE:.*]]*, i8*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC11strRealPropSSvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC11strRealPropSSvgTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC11strRealPropSSvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc var strRealProp : String

// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC11strFakePropSSvgTo"([[OPAQUE:.*]]*, i8*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC11strFakePropSSvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC11strFakePropSSvgTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC11strFakePropSSvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc var strFakeProp : String {
get {
return ""
}
set {}
}

// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC13nsstrRealPropSo8NSStringCvgTo"([[OPAQUE:.*]]*, i8*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC13nsstrRealPropSo8NSStringCvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC13nsstrRealPropSo8NSStringCvgTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC13nsstrRealPropSo8NSStringCvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc var nsstrRealProp : NSString

// CHECK: define hidden swiftcc %TSo8NSStringC* @"$s11objc_bridge3BasC13nsstrFakePropSo8NSStringCvg"(%T11objc_bridge3BasC* swiftself) {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC13nsstrFakePropSo8NSStringCvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC13nsstrFakePropSo8NSStringCvsTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc var nsstrFakeProp : NSString {
get {
return NSS
}
set {}
}

// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC9strResultSSyFTo"([[OPAQUE:.*]]*, i8*) unnamed_addr {{.*}} {
// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC9strResultSSyFTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
@objc func strResult() -> String { return "" }
// CHECK: define internal void @"$s11objc_bridge3BasC6strArg1sySS_tFTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC6strArg1sySS_tFTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc func strArg(s s: String) { }

// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC11nsstrResultSo8NSStringCyFTo"([[OPAQUE:.*]]*, i8*) unnamed_addr {{.*}} {
// CHECK: define internal [[OPAQUE:.*]]* @"$s11objc_bridge3BasC11nsstrResultSo8NSStringCyFTo"([[OPAQUE:.*]]*, i8*) {{[#0-9]*}} {
@objc func nsstrResult() -> NSString { return NSS }
// CHECK: define internal void @"$s11objc_bridge3BasC8nsstrArg1sySo8NSStringC_tFTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s11objc_bridge3BasC8nsstrArg1sySo8NSStringC_tFTo"([[OPAQUE:.*]]*, i8*, [[OPAQUE:.*]]*) {{[#0-9]*}} {
@objc func nsstrArg(s s: NSString) { }

override init() {
Expand Down
6 changes: 3 additions & 3 deletions test/IRGen/objc_class_export.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ struct BigStructWithNativeObjects {

@objc func drawInRect(dirty dirty: NSRect) {
}
// CHECK: define internal void @"$s17objc_class_export3FooC10drawInRect5dirtyySo6NSRectV_tFTo"([[OPAQUE:%.*]]*, i8*, [[NSRECT]]* byval align 8) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s17objc_class_export3FooC10drawInRect5dirtyySo6NSRectV_tFTo"([[OPAQUE:%.*]]*, i8*, [[NSRECT]]* byval align 8) {{[#0-9]*}} {
// CHECK: [[CAST:%[a-zA-Z0-9]+]] = bitcast [[OPAQUE]]* %0 to [[FOO]]*
// CHECK: call swiftcc void @"$s17objc_class_export3FooC10drawInRect5dirtyySo6NSRectV_tF"(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [[FOO]]* swiftself [[CAST]])
// CHECK: }
Expand All @@ -90,14 +90,14 @@ struct BigStructWithNativeObjects {
return NSRect(origin: NSPoint(x: 0, y: 0),
size: NSSize(width: 0, height: 0))
}
// CHECK: define internal void @"$s17objc_class_export3FooC6boundsSo6NSRectVyFTo"([[NSRECT]]* noalias nocapture sret, [[OPAQUE4:%.*]]*, i8*) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s17objc_class_export3FooC6boundsSo6NSRectVyFTo"([[NSRECT]]* noalias nocapture sret, [[OPAQUE4:%.*]]*, i8*) {{[#0-9]*}} {
// CHECK: [[CAST:%[a-zA-Z0-9]+]] = bitcast [[OPAQUE4]]* %1 to [[FOO]]*
// CHECK: call swiftcc { double, double, double, double } @"$s17objc_class_export3FooC6boundsSo6NSRectVyF"([[FOO]]* swiftself [[CAST]])

@objc func convertRectToBacking(r r: NSRect) -> NSRect {
return r
}
// CHECK: define internal void @"$s17objc_class_export3FooC20convertRectToBacking1rSo6NSRectVAG_tFTo"([[NSRECT]]* noalias nocapture sret, [[OPAQUE5:%.*]]*, i8*, [[NSRECT]]* byval align 8) unnamed_addr {{.*}} {
// CHECK: define internal void @"$s17objc_class_export3FooC20convertRectToBacking1rSo6NSRectVAG_tFTo"([[NSRECT]]* noalias nocapture sret, [[OPAQUE5:%.*]]*, i8*, [[NSRECT]]* byval align 8) {{[#0-9]*}} {
// CHECK: [[CAST:%[a-zA-Z0-9]+]] = bitcast [[OPAQUE5]]* %1 to [[FOO]]*
// CHECK: call swiftcc { double, double, double, double } @"$s17objc_class_export3FooC20convertRectToBacking1rSo6NSRectVAG_tF"(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [[FOO]]* swiftself [[CAST]])

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/objc_dealloc.sil
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ bb0(%0 : @unowned $X, %1 : @unowned $SwiftGizmo):
return %7 : $() // id: %8
}

// CHECK: define internal void @"$s12objc_dealloc10SwiftGizmoCfDTo"([[OPAQUE:%.*]]*, i8*) unnamed_addr
// CHECK: define internal void @"$s12objc_dealloc10SwiftGizmoCfDTo"([[OPAQUE:%.*]]*, i8*) {{[#0-9]*}} {
sil [ossa] @$s12objc_dealloc10SwiftGizmoCfDTo : $@convention(objc_method) (SwiftGizmo) -> () {
bb0(%0 : @unowned $SwiftGizmo):
// CHECK-NEXT: entry
Expand Down
56 changes: 56 additions & 0 deletions test/IRGen/objc_function_merge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -O %s -module-name=test -o %t/a.out
// RUN: %target-build-swift -O %s -module-name=test -emit-ir | %FileCheck --check-prefix=CHECK-IR %s
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s
// REQUIRES: executable_test
// REQUIRES: objc_interop

// In some places Foundation is comparing ObjC method pointers.
// Therefore LLVM's function merging pass must not create aliases for identical
// functions, but create thunks. This can be ensured if ObjC methods are not
// created with the unnamed_addr attribute.

import Foundation

class Base: NSObject, NSSecureCoding {
@objc public class var supportsSecureCoding: Bool {
return true
}

@objc let s: String

func encode(with coder: NSCoder) {
coder.encode(s, forKey: #keyPath(s))
}

init(s: String) {
self.s = s
}

required init?(coder: NSCoder) {
self.s = coder.value(forKey: #keyPath(s)) as! String
}
}

class Derived : Base {
// Make sure the overridden method is not merged with the base method (without
// creating a thunk), so that the method pointers remain distinct.
@objc public class override var supportsSecureCoding: Bool {
return true
}
}


// Check if the objc methods are not generated with the unnamed_addr attribute.
// CHECK-IR-DAG: define {{.*}} @"$s4test4BaseC20supportsSecureCodingSbvgZTo"({{[^\)]*}}) #{{[0-9]+}} {
// CHECK-IR-DAG: define {{.*}} @"$s4test4BaseC6encode4withySo7NSCoderC_tFTo"({{[^\)]*}}) #{{[0-9]+}} {
// CHECK-IR-DAG: define {{.*}} @"$s4test7DerivedC20supportsSecureCodingSbvgZTo"({{[^\)]*}}) #{{[0-9]+}} {

let d = Derived(s: "")
if #available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *) {
// Check that we don't crash here.
_ = try NSKeyedArchiver.archivedData(withRootObject: d, requiringSecureCoding: true)
}
// CHECK: okay
print("okay")
2 changes: 1 addition & 1 deletion test/IRGen/objc_subscripts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

@objc class SomeObject {
@objc subscript (i : Int) -> SomeObject {
// CHECK: define internal [[OPAQUE0:%.*]]* @"$s15objc_subscripts10SomeObjectCyACSicigTo"([[OPAQUE1]]*, i8*, i64) unnamed_addr
// CHECK: define internal [[OPAQUE0:%.*]]* @"$s15objc_subscripts10SomeObjectCyACSicigTo"([[OPAQUE1]]*, i8*, i64) {{[#0-9]*}} {
get {
// CHECK: call swiftcc %T15objc_subscripts10SomeObjectC* @"$s15objc_subscripts10SomeObjectCyACSicig"
return self
Expand Down