forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathProtocolInfo.h
195 lines (157 loc) · 5.91 KB
/
ProtocolInfo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//===--- ProtocolInfo.h - Abstract protocol witness layout ------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines types for representing the abstract layout of a
// protocol.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_PROTOCOLINFO_H
#define SWIFT_IRGEN_PROTOCOLINFO_H
#include "swift/AST/Decl.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ArrayRef.h"
#include "ValueWitness.h"
namespace swift {
class CanType;
class Decl;
class ProtocolConformance;
class ProtocolDecl;
namespace irgen {
class ConformanceInfo; // private to GenProto.cpp
class IRGenModule;
class TypeInfo;
/// A class which encapsulates an index into a witness table.
class WitnessIndex {
unsigned Value : 31;
unsigned IsPrefix : 1;
public:
WitnessIndex() = default;
WitnessIndex(ValueWitness index) : Value(unsigned(index)) {}
explicit WitnessIndex(unsigned index, bool isPrefix)
: Value(index), IsPrefix(isPrefix) {}
unsigned getValue() const { return Value; }
bool isPrefix() const { return IsPrefix; }
};
/// A witness to a specific element of a protocol. Every
/// ProtocolTypeInfo stores one of these for each declaration in the
/// protocol.
///
/// The structure of a witness varies by the type of declaration:
/// - a function requires a single witness, the function;
/// - a variable requires two witnesses, a getter and a setter;
/// - a subscript requires two witnesses, a getter and a setter;
/// - a type requires a pointer to the metadata for that type and
/// to witness tables for each of the protocols it obeys.
class WitnessTableEntry {
Decl *Member;
WitnessIndex BeginIndex;
WitnessTableEntry(Decl *member, WitnessIndex begin)
: Member(member), BeginIndex(begin) {}
public:
WitnessTableEntry() = default;
Decl *getMember() const {
return Member;
}
static WitnessTableEntry forPrefixBase(ProtocolDecl *proto) {
return WitnessTableEntry(proto, WitnessIndex(0, /*isPrefix=*/ true));
}
static WitnessTableEntry forOutOfLineBase(ProtocolDecl *proto,
WitnessIndex index) {
return WitnessTableEntry(proto, index);
}
/// Is this a base-protocol entry?
bool isBase() const { return isa<ProtocolDecl>(Member); }
/// Is the table for this base-protocol entry "out of line",
/// i.e. there is a witness which indirectly points to it, or is
/// it a prefix of the layout of this protocol?
bool isOutOfLineBase() const {
assert(isBase());
return !BeginIndex.isPrefix();
}
/// Return the index at which to find the table for this
/// base-protocol entry.
WitnessIndex getOutOfLineBaseIndex() const {
assert(isOutOfLineBase());
return BeginIndex;
}
static WitnessTableEntry forFunction(AbstractFunctionDecl *func,
WitnessIndex index) {
return WitnessTableEntry(func, index);
}
bool isFunction() const { return isa<AbstractFunctionDecl>(Member); }
WitnessIndex getFunctionIndex() const {
assert(isFunction());
return BeginIndex;
}
static WitnessTableEntry forAssociatedType(AssociatedTypeDecl *ty,
WitnessIndex index) {
return WitnessTableEntry(ty, index);
}
bool isAssociatedType() const { return isa<AssociatedTypeDecl>(Member); }
WitnessIndex getAssociatedTypeIndex() const {
assert(isAssociatedType());
return BeginIndex;
}
};
/// An abstract description of a protocol.
class ProtocolInfo {
/// A singly-linked-list of all the protocols that have been laid out.
const ProtocolInfo *NextConverted;
friend class TypeConverter;
/// The number of witnesses in the protocol.
unsigned NumWitnesses;
/// The number of table entries in this protocol layout.
unsigned NumTableEntries;
/// A table of all the conformances we've needed so far for this
/// protocol. We expect this to be quite small for most protocols.
mutable llvm::SmallDenseMap<const ProtocolConformance*, ConformanceInfo*, 2>
Conformances;
WitnessTableEntry *getEntriesBuffer() {
return reinterpret_cast<WitnessTableEntry*>(this+1);
}
const WitnessTableEntry *getEntriesBuffer() const {
return reinterpret_cast<const WitnessTableEntry*>(this+1);
}
ProtocolInfo(unsigned numWitnesses, ArrayRef<WitnessTableEntry> table)
: NumWitnesses(numWitnesses), NumTableEntries(table.size()) {
std::memcpy(getEntriesBuffer(), table.data(),
sizeof(WitnessTableEntry) * table.size());
}
static ProtocolInfo *create(unsigned numWitnesses,
ArrayRef<WitnessTableEntry> table);
public:
const ConformanceInfo &getConformance(IRGenModule &IGM,
ProtocolDecl *protocol,
const ProtocolConformance *conf) const;
unsigned getNumWitnesses() const {
return NumWitnesses;
}
unsigned getNumTableEntries() const {
return NumTableEntries;
}
ArrayRef<WitnessTableEntry> getWitnessEntries() const {
return ArrayRef<WitnessTableEntry>(getEntriesBuffer(),
getNumTableEntries());
}
const WitnessTableEntry &getWitnessEntry(Decl *member) const {
// FIXME: do a binary search if the number of witnesses is large
// enough.
for (auto &witness : getWitnessEntries())
if (witness.getMember() == member)
return witness;
llvm_unreachable("didn't find entry for member!");
}
~ProtocolInfo();
};
} // end namespace irgen
} // end namespace swift
#endif