Skip to content

Commit 88d2feb

Browse files
authored
Merge pull request swiftlang#18528 from DougGregor/irgen-objc-refcount
[IRGen] Use a more precise computation for the kind of reference count.
2 parents 0bd682e + f37e9fc commit 88d2feb

File tree

12 files changed

+133
-85
lines changed

12 files changed

+133
-85
lines changed

include/swift/AST/ReferenceCounting.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===--- ReferenceCounting.h ------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_AST_REFERENCE_COUNTING_H
14+
#define SWIFT_AST_REFERENCE_COUNTING_H
15+
16+
namespace swift {
17+
18+
/// The kind of reference counting implementation a heap object uses.
19+
enum class ReferenceCounting : uint8_t {
20+
/// The object uses native Swift reference counting.
21+
Native,
22+
23+
/// The object uses ObjC reference counting.
24+
///
25+
/// When ObjC interop is enabled, native Swift class objects are also ObjC
26+
/// reference counting compatible. Swift non-class heap objects are never
27+
/// ObjC reference counting compatible.
28+
///
29+
/// Blocks are always ObjC reference counting compatible.
30+
ObjC,
31+
32+
/// The object uses _Block_copy/_Block_release reference counting.
33+
///
34+
/// This is a strict subset of ObjC; all blocks are also ObjC reference
35+
/// counting compatible. The block is assumed to have already been moved to
36+
/// the heap so that _Block_copy returns the same object back.
37+
Block,
38+
39+
/// The object has an unknown reference counting implementation.
40+
///
41+
/// This uses maximally-compatible reference counting entry points in the
42+
/// runtime.
43+
Unknown,
44+
45+
/// Cases prior to this one are binary-compatible with Unknown reference
46+
/// counting.
47+
LastUnknownCompatible = Unknown,
48+
49+
/// The object has an unknown reference counting implementation and
50+
/// the reference value may contain extra bits that need to be masked.
51+
///
52+
/// This uses maximally-compatible reference counting entry points in the
53+
/// runtime, with a masking layer on top. A bit inside the pointer is used
54+
/// to signal native Swift refcounting.
55+
Bridge,
56+
57+
/// The object uses ErrorType's reference counting entry points.
58+
Error,
59+
};
60+
61+
} // end namespace swift
62+
63+
#endif

include/swift/AST/Types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ namespace swift {
5454
class GenericParamList;
5555
class GenericSignature;
5656
class Identifier;
57+
enum class ReferenceCounting : uint8_t;
5758
enum class ResilienceExpansion : unsigned;
5859
class SILModule;
5960
class SILType;
@@ -843,6 +844,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
843844
/// Swift-native reference counting?
844845
bool usesNativeReferenceCounting(ResilienceExpansion resilience);
845846

847+
/// Given that this type is a reference type, which kind of reference
848+
/// counting does it use?
849+
ReferenceCounting getReferenceCounting(ResilienceExpansion resilience);
850+
846851
/// Determines whether this type has a bridgeable object
847852
/// representation, i.e., whether it is always represented as a single
848853
/// (non-nil) pointer that can be unknown-retained and

lib/AST/Type.cpp

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/ExistentialLayout.h"
2121
#include "swift/AST/GenericSignatureBuilder.h"
22+
#include "swift/AST/ReferenceCounting.h"
2223
#include "swift/AST/TypeVisitor.h"
2324
#include "swift/AST/TypeWalker.h"
2425
#include "swift/AST/Decl.h"
@@ -4046,21 +4047,29 @@ bool UnownedStorageType::isLoadable(ResilienceExpansion resilience) const {
40464047
return ty->usesNativeReferenceCounting(resilience);
40474048
}
40484049

4049-
static bool doesOpaqueClassUseNativeReferenceCounting(const ASTContext &ctx) {
4050-
return !ctx.LangOpts.EnableObjCInterop;
4051-
}
4052-
4053-
static bool usesNativeReferenceCounting(ClassDecl *theClass,
4054-
ResilienceExpansion resilience) {
4050+
static ReferenceCounting getClassReferenceCounting(
4051+
ClassDecl *theClass,
4052+
ResilienceExpansion resilience) {
40554053
// TODO: Resilience? there might be some legal avenue of changing this.
40564054
while (auto superclass = theClass->getSuperclassDecl()) {
40574055
theClass = superclass;
40584056
}
4059-
return !theClass->hasClangNode();
4057+
4058+
return theClass->hasClangNode()
4059+
? ReferenceCounting::ObjC
4060+
: ReferenceCounting::Native;
40604061
}
40614062

4062-
bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
4063+
ReferenceCounting TypeBase::getReferenceCounting(
4064+
ResilienceExpansion resilience) {
40634065
CanType type = getCanonicalType();
4066+
ASTContext &ctx = type->getASTContext();
4067+
4068+
// In the absence of Objective-C interoperability, everything uses native
4069+
// reference counting.
4070+
if (!ctx.LangOpts.EnableObjCInterop)
4071+
return ReferenceCounting::Native;
4072+
40644073
switch (type->getKind()) {
40654074
#define SUGARED_TYPE(id, parent) case TypeKind::id:
40664075
#define TYPE(id, parent)
@@ -4069,27 +4078,29 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
40694078

40704079
case TypeKind::BuiltinNativeObject:
40714080
case TypeKind::SILBox:
4072-
return true;
4081+
return ReferenceCounting::Native;
40734082

4074-
case TypeKind::BuiltinUnknownObject:
40754083
case TypeKind::BuiltinBridgeObject:
4076-
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4084+
return ReferenceCounting::Bridge;
4085+
4086+
case TypeKind::BuiltinUnknownObject:
4087+
return ReferenceCounting::Unknown;
40774088

40784089
case TypeKind::Class:
4079-
return ::usesNativeReferenceCounting(cast<ClassType>(type)->getDecl(),
4080-
resilience);
4090+
return getClassReferenceCounting(cast<ClassType>(type)->getDecl(),
4091+
resilience);
40814092
case TypeKind::BoundGenericClass:
4082-
return ::usesNativeReferenceCounting(
4093+
return getClassReferenceCounting(
40834094
cast<BoundGenericClassType>(type)->getDecl(),
4084-
resilience);
4095+
resilience);
40854096
case TypeKind::UnboundGeneric:
4086-
return ::usesNativeReferenceCounting(
4097+
return getClassReferenceCounting(
40874098
cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl()),
4088-
resilience);
4099+
resilience);
40894100

40904101
case TypeKind::DynamicSelf:
40914102
return cast<DynamicSelfType>(type).getSelfType()
4092-
->usesNativeReferenceCounting(resilience);
4103+
->getReferenceCounting(resilience);
40934104

40944105
case TypeKind::Archetype: {
40954106
auto archetype = cast<ArchetypeType>(type);
@@ -4098,17 +4109,17 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
40984109
assert(archetype->requiresClass() ||
40994110
(layout && layout->isRefCounted()));
41004111
if (auto supertype = archetype->getSuperclass())
4101-
return supertype->usesNativeReferenceCounting(resilience);
4102-
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4112+
return supertype->getReferenceCounting(resilience);
4113+
return ReferenceCounting::Unknown;
41034114
}
41044115

41054116
case TypeKind::Protocol:
41064117
case TypeKind::ProtocolComposition: {
4107-
auto layout = getExistentialLayout();
4118+
auto layout = type->getExistentialLayout();
41084119
assert(layout.requiresClass() && "Opaque existentials don't use refcounting");
41094120
if (auto superclass = layout.getSuperclass())
4110-
return superclass->usesNativeReferenceCounting(resilience);
4111-
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4121+
return superclass->getReferenceCounting(resilience);
4122+
return ReferenceCounting::Unknown;
41124123
}
41134124

41144125
case TypeKind::Function:
@@ -4145,6 +4156,10 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
41454156
llvm_unreachable("Unhandled type kind!");
41464157
}
41474158

4159+
bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
4160+
return getReferenceCounting(resilience) == ReferenceCounting::Native;
4161+
}
4162+
41484163
//
41494164
// SILBoxType implementation
41504165
//

lib/IRGen/GenClass.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,7 @@ using namespace irgen;
6363
/// What reference counting mechanism does a class-like type have?
6464
ReferenceCounting irgen::getReferenceCountingForType(IRGenModule &IGM,
6565
CanType type) {
66-
// If ObjC interop is disabled, we have a Swift refcount.
67-
if (!IGM.ObjCInterop)
68-
return ReferenceCounting::Native;
69-
70-
if (type->usesNativeReferenceCounting(ResilienceExpansion::Maximal))
71-
return ReferenceCounting::Native;
72-
73-
// Class-constrained archetypes and existentials that don't use
74-
// native reference counting and yet have a superclass must be
75-
// using ObjC reference counting.
76-
auto superclass = type->getSuperclass();
77-
if (superclass)
78-
return ReferenceCounting::ObjC;
79-
80-
// Otherwise, it could be either one.
81-
return ReferenceCounting::Unknown;
66+
return type->getReferenceCounting(ResilienceExpansion::Maximal);
8267
}
8368

8469
namespace {

lib/IRGen/GenClass.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ namespace irgen {
4848
class StructLayout;
4949
class TypeInfo;
5050

51-
enum class ReferenceCounting : unsigned char;
5251
enum class ClassDeallocationKind : unsigned char;
5352
enum class FieldAccess : uint8_t;
5453

lib/IRGen/IRGen.h

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -82,49 +82,6 @@ enum IsABIAccessible_t : bool {
8282
IsABIAccessible = true
8383
};
8484

85-
/// The kind of reference counting implementation a heap object uses.
86-
enum class ReferenceCounting : uint8_t {
87-
/// The object uses native Swift reference counting.
88-
Native,
89-
90-
/// The object uses ObjC reference counting.
91-
///
92-
/// When ObjC interop is enabled, native Swift class objects are also ObjC
93-
/// reference counting compatible. Swift non-class heap objects are never
94-
/// ObjC reference counting compatible.
95-
///
96-
/// Blocks are always ObjC reference counting compatible.
97-
ObjC,
98-
99-
/// The object uses _Block_copy/_Block_release reference counting.
100-
///
101-
/// This is a strict subset of ObjC; all blocks are also ObjC reference
102-
/// counting compatible. The block is assumed to have already been moved to
103-
/// the heap so that _Block_copy returns the same object back.
104-
Block,
105-
106-
/// The object has an unknown reference counting implementation.
107-
///
108-
/// This uses maximally-compatible reference counting entry points in the
109-
/// runtime.
110-
Unknown,
111-
112-
/// Cases prior to this one are binary-compatible with Unknown reference
113-
/// counting.
114-
LastUnknownCompatible = Unknown,
115-
116-
/// The object has an unknown reference counting implementation and
117-
/// the reference value may contain extra bits that need to be masked.
118-
///
119-
/// This uses maximally-compatible reference counting entry points in the
120-
/// runtime, with a masking layer on top. A bit inside the pointer is used
121-
/// to signal native Swift refcounting.
122-
Bridge,
123-
124-
/// The object uses ErrorType's reference counting entry points.
125-
Error,
126-
};
127-
12885
/// The atomicity of a reference counting operation to be used.
12986
enum class Atomicity : bool {
13087
/// Atomic reference counting operations should be used.

lib/IRGen/IRGenFunction.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ namespace irgen {
6060
class Scope;
6161
class TypeInfo;
6262
enum class ValueWitness : unsigned;
63-
enum class ReferenceCounting : unsigned char;
6463

6564
/// IRGenFunction - Primary class for emitting LLVM instructions for a
6665
/// specific function.

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "SwiftTargetInfo.h"
2323
#include "swift/AST/Decl.h"
2424
#include "swift/AST/Module.h"
25+
#include "swift/AST/ReferenceCounting.h"
2526
#include "swift/Basic/ClusteredBitVector.h"
2627
#include "swift/Basic/LLVM.h"
2728
#include "swift/Basic/OptimizationMode.h"
@@ -133,7 +134,6 @@ namespace irgen {
133134
class TypeConverter;
134135
class TypeInfo;
135136
enum class ValueWitness : unsigned;
136-
enum class ReferenceCounting : unsigned char;
137137

138138
class IRGenModule;
139139

lib/IRGen/TypeInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#define SWIFT_IRGEN_TYPEINFO_H
2727

2828
#include "IRGen.h"
29+
#include "swift/AST/ReferenceCounting.h"
2930
#include "llvm/ADT/MapVector.h"
3031

3132
namespace llvm {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Foundation
2+
3+
@objc class Bar : NSObject { }

0 commit comments

Comments
 (0)