Skip to content

Commit 4d39506

Browse files
committed
[IRGen] Use a more precise computation for the kind of reference count.
TypeBase::usesNativeReferenceCounting() was doing a lot of work to find the class that a type refers to, then determine whether it would use the native reference-counting scheme. Its primary caller in IRGen would use an overly-conservative approximation to decide between the “Objective-C” and “unknown” cases, which resulted in uses of “unknown” reference counting for some obviously-ObjC cases (e.g., values of “NSObject”). Moreover, the approximation would try to call into the type checker (because it relied unnecessarily on the superclass *type* of a class declaration), causing an assertion. Fixes rdar://problem/42828798.
1 parent 6ade7c1 commit 4d39506

File tree

12 files changed

+136
-85
lines changed

12 files changed

+136
-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: 41 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,31 @@ 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+
// Determine which reference-counting scheme to use for an unknown object.
4069+
bool objCInterop = ctx.LangOpts.EnableObjCInterop;
4070+
auto getUnknownObjectReferenceCounting = [objCInterop] {
4071+
return objCInterop ? ReferenceCounting::Unknown
4072+
: ReferenceCounting::Native;
4073+
};
4074+
40644075
switch (type->getKind()) {
40654076
#define SUGARED_TYPE(id, parent) case TypeKind::id:
40664077
#define TYPE(id, parent)
@@ -4069,27 +4080,30 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
40694080

40704081
case TypeKind::BuiltinNativeObject:
40714082
case TypeKind::SILBox:
4072-
return true;
4083+
return ReferenceCounting::Native;
40734084

4074-
case TypeKind::BuiltinUnknownObject:
40754085
case TypeKind::BuiltinBridgeObject:
4076-
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4086+
return objCInterop ? ReferenceCounting::Bridge
4087+
: ReferenceCounting::Native;
4088+
4089+
case TypeKind::BuiltinUnknownObject:
4090+
return getUnknownObjectReferenceCounting();
40774091

40784092
case TypeKind::Class:
4079-
return ::usesNativeReferenceCounting(cast<ClassType>(type)->getDecl(),
4080-
resilience);
4093+
return getClassReferenceCounting(cast<ClassType>(type)->getDecl(),
4094+
resilience);
40814095
case TypeKind::BoundGenericClass:
4082-
return ::usesNativeReferenceCounting(
4096+
return getClassReferenceCounting(
40834097
cast<BoundGenericClassType>(type)->getDecl(),
4084-
resilience);
4098+
resilience);
40854099
case TypeKind::UnboundGeneric:
4086-
return ::usesNativeReferenceCounting(
4100+
return getClassReferenceCounting(
40874101
cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl()),
4088-
resilience);
4102+
resilience);
40894103

40904104
case TypeKind::DynamicSelf:
40914105
return cast<DynamicSelfType>(type).getSelfType()
4092-
->usesNativeReferenceCounting(resilience);
4106+
->getReferenceCounting(resilience);
40934107

40944108
case TypeKind::Archetype: {
40954109
auto archetype = cast<ArchetypeType>(type);
@@ -4098,17 +4112,17 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
40984112
assert(archetype->requiresClass() ||
40994113
(layout && layout->isRefCounted()));
41004114
if (auto supertype = archetype->getSuperclass())
4101-
return supertype->usesNativeReferenceCounting(resilience);
4102-
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4115+
return supertype->getReferenceCounting(resilience);
4116+
return getUnknownObjectReferenceCounting();
41034117
}
41044118

41054119
case TypeKind::Protocol:
41064120
case TypeKind::ProtocolComposition: {
4107-
auto layout = getExistentialLayout();
4121+
auto layout = type->getExistentialLayout();
41084122
assert(layout.requiresClass() && "Opaque existentials don't use refcounting");
41094123
if (auto superclass = layout.getSuperclass())
4110-
return superclass->usesNativeReferenceCounting(resilience);
4111-
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4124+
return superclass->getReferenceCounting(resilience);
4125+
return getUnknownObjectReferenceCounting();
41124126
}
41134127

41144128
case TypeKind::Function:
@@ -4145,6 +4159,10 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
41454159
llvm_unreachable("Unhandled type kind!");
41464160
}
41474161

4162+
bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
4163+
return getReferenceCounting(resilience) == ReferenceCounting::Native;
4164+
}
4165+
41484166
//
41494167
// SILBoxType implementation
41504168
//

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)