Skip to content

Commit 2a87b68

Browse files
authored
Merge pull request #24758 from slavapestov/dynamic-self-in-convenience-init
IRGen: Fix DynamicSelfType metadata recovery in @objc convenience inializers
2 parents 1a0c785 + 22cea6c commit 2a87b68

File tree

4 files changed

+67
-86
lines changed

4 files changed

+67
-86
lines changed

lib/IRGen/GenHeap.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,17 +1684,43 @@ void IRGenFunction::emit##ID(llvm::Value *value, Address src) { \
16841684

16851685
llvm::Value *IRGenFunction::getLocalSelfMetadata() {
16861686
assert(LocalSelf && "no local self metadata");
1687+
1688+
// If we already have a metatype, just return it.
1689+
if (SelfKind == SwiftMetatype)
1690+
return LocalSelf;
1691+
1692+
// We need to materialize a metatype. Emit the code for that once at the
1693+
// top of the function and cache the result.
1694+
1695+
// This is a slight optimization in the case of repeated access, but also
1696+
// needed for correctness; when an @objc convenience initializer replaces
1697+
// the 'self' value, we don't keep track of what the new 'self' value is
1698+
// in IRGen, so we can't just grab the first function argument and assume
1699+
// it's a valid 'self' at the point where DynamicSelfType metadata is needed.
1700+
1701+
// Note that if DynamicSelfType was modeled properly as an opened archetype,
1702+
// none of this would be an issue since it would be always be associated
1703+
// with the correct value.
1704+
1705+
llvm::IRBuilderBase::InsertPointGuard guard(Builder);
1706+
Builder.SetInsertPoint(&CurFn->getEntryBlock(),
1707+
CurFn->getEntryBlock().begin());
1708+
16871709
switch (SelfKind) {
16881710
case SwiftMetatype:
1689-
return LocalSelf;
1711+
llvm_unreachable("Already handled");
16901712
case ObjCMetatype:
1691-
return emitObjCMetadataRefForMetadata(*this, LocalSelf);
1713+
LocalSelf = emitObjCMetadataRefForMetadata(*this, LocalSelf);
1714+
SelfKind = SwiftMetatype;
1715+
break;
16921716
case ObjectReference:
1693-
return emitDynamicTypeOfOpaqueHeapObject(*this, LocalSelf,
1717+
LocalSelf = emitDynamicTypeOfOpaqueHeapObject(*this, LocalSelf,
16941718
MetatypeRepresentation::Thick);
1719+
SelfKind = SwiftMetatype;
1720+
break;
16951721
}
16961722

1697-
llvm_unreachable("Not a valid LocalSelfKind.");
1723+
return LocalSelf;
16981724
}
16991725

17001726
/// Given a non-tagged object pointer, load a pointer to its class object.

lib/IRGen/IRBuilder.h

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -109,67 +109,6 @@ class IRBuilder : public IRBuilderBase {
109109
IRBuilderBase::SetInsertPoint(I);
110110
}
111111

112-
/// A stable insertion point in the function. "Stable" means that
113-
/// it will point to the same location in the function, even if
114-
/// instructions are subsequently added to the current basic block.
115-
class StableIP {
116-
/// Either an instruction that we're inserting after or the basic
117-
/// block that we're inserting at the beginning of.
118-
using UnionTy = llvm::PointerUnion<llvm::Instruction *, llvm::BasicBlock *>;
119-
UnionTy After;
120-
public:
121-
StableIP() = default;
122-
explicit StableIP(const IRBuilder &Builder) {
123-
if (!Builder.hasValidIP()) {
124-
After = UnionTy();
125-
assert(!isValid());
126-
return;
127-
}
128-
129-
llvm::BasicBlock *curBlock = Builder.GetInsertBlock();
130-
assert(Builder.GetInsertPoint() == curBlock->end());
131-
if (curBlock->empty())
132-
After = curBlock;
133-
else
134-
After = &curBlock->back();
135-
}
136-
137-
/// Does this stable IP point to a valid location?
138-
bool isValid() const {
139-
return !After.isNull();
140-
}
141-
142-
/// Insert an unparented instruction at this insertion point.
143-
/// Note that inserting multiple instructions at an IP will cause
144-
/// them to end up in reverse order.
145-
void insert(llvm::Instruction *I) {
146-
assert(isValid() && "inserting at invalid location!");
147-
assert(I->getParent() == nullptr);
148-
if (auto *block = After.dyn_cast<llvm::BasicBlock*>()) {
149-
block->getInstList().push_front(I);
150-
} else {
151-
llvm::Instruction *afterInsn = After.get<llvm::Instruction*>();
152-
afterInsn->getParent()->getInstList().insertAfter(
153-
afterInsn->getIterator(), I);
154-
}
155-
}
156-
157-
// Support for being placed in pointer unions.
158-
void *getOpaqueValue() const { return After.getOpaqueValue(); }
159-
static StableIP getFromOpaqueValue(void *p) {
160-
StableIP result;
161-
result.After = UnionTy::getFromOpaqueValue(p);
162-
return result;
163-
}
164-
enum { NumLowBitsAvailable
165-
= llvm::PointerLikeTypeTraits<UnionTy>::NumLowBitsAvailable };
166-
};
167-
168-
/// Capture a stable reference to the current IP.
169-
StableIP getStableIP() const {
170-
return StableIP(*this);
171-
}
172-
173112
/// Return the LLVM module we're inserting into.
174113
llvm::Module *getModule() const {
175114
if (auto BB = GetInsertBlock())
@@ -397,23 +336,4 @@ class IRBuilder : public IRBuilderBase {
397336
} // end namespace irgen
398337
} // end namespace swift
399338

400-
namespace llvm {
401-
template <> struct PointerLikeTypeTraits<swift::irgen::IRBuilder::StableIP> {
402-
using type = swift::irgen::IRBuilder::StableIP;
403-
404-
public:
405-
static void *getAsVoidPointer(type IP) {
406-
return IP.getOpaqueValue();
407-
}
408-
static type getFromVoidPointer(void *p) {
409-
return type::getFromOpaqueValue(p);
410-
}
411-
412-
// The number of bits available are the min of the two pointer types.
413-
enum {
414-
NumLowBitsAvailable = type::NumLowBitsAvailable
415-
};
416-
};
417-
}
418-
419339
#endif

test/IRGen/dynamic_self_metadata.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ class C {
5050
// CHECK-LABEL: define hidden swiftcc i64 @"$s21dynamic_self_metadata1CC0A18SelfConformingTypeACXDSgyF"(%T21dynamic_self_metadata1CC* swiftself)
5151
// CHECK: [[SELF:%.*]] = bitcast %T21dynamic_self_metadata1CC* %0 to %objc_object*
5252
// CHECK: [[SELF_TYPE:%.*]] = call %swift.type* @swift_getObjectType(%objc_object* [[SELF]])
53-
// CHECK: [[SELF:%.*]] = bitcast %T21dynamic_self_metadata1CC* %0 to %objc_object*
54-
// CHECK: [[SELF_TYPE:%.*]] = call %swift.type* @swift_getObjectType(%objc_object* [[SELF]])
5553
// CHECK: [[METADATA_RESPONSE:%.*]] = call swiftcc %swift.metadata_response @"$s21dynamic_self_metadata1GVMa"(i64 0, %swift.type* [[SELF_TYPE]])
5654
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0
5755
// CHECK: call i8** @swift_getWitnessTable(%swift.protocol_conformance_descriptor* bitcast ({{.*}} @"$s21dynamic_self_metadata1GVyxGAA1PAAMc" to %swift.protocol_conformance_descriptor*), %swift.type* [[METADATA]], i8*** undef)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-build-swift %s -o %t/main -swift-version 5
4+
// RUN: %target-codesign %t/main
5+
// RUN: %target-run %t/main
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: objc_interop
9+
10+
import Foundation
11+
import StdlibUnittest
12+
13+
func foo(_ x: @escaping () -> ()) { x() }
14+
15+
public class C {
16+
var x: Int = 0
17+
18+
init(blah: ()) {}
19+
20+
@objc convenience init() {
21+
self.init(blah: ())
22+
23+
foo { [weak self] in
24+
guard let `self` = self else { return }
25+
self.x += 1
26+
}
27+
}
28+
}
29+
30+
var ConvenienceInitSelfTest = TestSuite("ConvenienceInitSelf")
31+
32+
ConvenienceInitSelfTest.test("SelfMetadata") {
33+
let c = C()
34+
expectEqual(c.x, 1)
35+
}
36+
37+
runAllTests()

0 commit comments

Comments
 (0)