Skip to content

Commit 872bf40

Browse files
committed
[sil-optimizer] Centralize how we send out serialization notifications.
Previously SILModule contained two different pathways for the deserializer to send notifications that it had created functions: 1. A list of function pointers that were called when a function's body was deserialized. This was added recently so that access enforcement elimination is run on newly deserialized SIL code if we have already eliminated access enforcement from the module. 2. SILModule::SerializationCallback. This is an implementation of the full callback interface and is used by the SILModule to update linkage and other sorts of book keeping. To fix the pass manager notification infrastructure, I need to be able to send notifications to a SILPassManager when deserializing. I also need to be able to eliminate these callbacks when a SILPassManager is destroyed. These requirements are incompatible with the current two implementations since: (2) is an implementation detail of SILModule and (1) only notifies on function bodies being deserialized instead of the creation of new declarations (what the caller analysis wants). Rather than adding a third group of callbacks, this commit refactors the infrastructure in such a way that all of these use cases can use one implementation. This is done by: 1. Lifting the interface of SerializedSILLoader::Callback into a base notification protocol for deserialization called DeserializationNotificationHandlerBase and its base no-op implementation into an implementation of the aforementioned protocol: DeserializationNotificationHandler. 2. Changing SILModule::SerializationCallback to implement DeserializationNotificationHandler. 3. Creating a class called FunctionBodyDeserializationNotificationHandler that takes in a function pointer and uses that to just override the didDeserializeFunctionBody. This eliminates the need for the specific function body deserialization list. 4. Replacing the state associated with the two other pathways with a single DeserializationNotificationHandlerSet class that contains a set of DeserializationNotificationHandler and chains notifications to them. This set implements DeserializationNotificationHandlerBase so we know that its implementation will always be in sync with DeserializationNotificationHandler. rdar://42301529
1 parent cd74150 commit 872bf40

File tree

10 files changed

+350
-103
lines changed

10 files changed

+350
-103
lines changed

include/swift/SIL/Notifications.h

Lines changed: 224 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,232 @@
1313
#ifndef SWIFT_SIL_NOTIFICATIONS_H
1414
#define SWIFT_SIL_NOTIFICATIONS_H
1515

16+
#include "swift/Basic/LLVM.h"
17+
#include "swift/Basic/STLExtras.h"
18+
#include "llvm/ADT/PointerUnion.h"
19+
#include "llvm/ADT/SmallVector.h"
20+
#include <memory>
21+
1622
namespace swift {
1723

1824
class SILNode;
25+
class ModuleDecl;
26+
class SILFunction;
27+
class SILWitnessTable;
28+
class SILDefaultWitnessTable;
29+
class SILGlobalVariable;
30+
class SILVTable;
31+
32+
/// An abstract class for handling SIL deserialization notifications.
33+
///
34+
/// This is an interface that should be implemented by clients that wish to
35+
/// maintain a list of notification handlers. In contrast, handler
36+
/// implementations should instead subclass DeserializationNotificationHandler
37+
/// so that default no-op implementations can be inherited and so that it can be
38+
/// passed into DeserializationNotificationHandlerSet.
39+
class DeserializationNotificationHandlerBase {
40+
public:
41+
/// Observe that we deserialized a function declaration.
42+
virtual void didDeserialize(ModuleDecl *mod, SILFunction *fn) = 0;
43+
44+
/// Observe that we successfully deserialized a function body.
45+
virtual void didDeserializeFunctionBody(ModuleDecl *mod, SILFunction *fn) = 0;
46+
47+
/// Observe that we successfully deserialized a witness table's entries.
48+
virtual void didDeserializeWitnessTableEntries(ModuleDecl *mod,
49+
SILWitnessTable *wt) = 0;
50+
51+
/// Observe that we successfully deserialized a default witness table's
52+
/// entries.
53+
virtual void
54+
didDeserializeDefaultWitnessTableEntries(ModuleDecl *mod,
55+
SILDefaultWitnessTable *wt) = 0;
56+
57+
/// Observe that we deserialized a global variable declaration.
58+
virtual void didDeserialize(ModuleDecl *mod, SILGlobalVariable *var) = 0;
59+
60+
/// Observe that we deserialized a v-table declaration.
61+
virtual void didDeserialize(ModuleDecl *mod, SILVTable *vtable) = 0;
62+
63+
/// Observe that we deserialized a witness-table declaration.
64+
virtual void didDeserialize(ModuleDecl *mod, SILWitnessTable *wtable) = 0;
65+
66+
/// Observe that we deserialized a default witness-table declaration.
67+
virtual void didDeserialize(ModuleDecl *mod,
68+
SILDefaultWitnessTable *wtable) = 0;
69+
70+
virtual ~DeserializationNotificationHandlerBase() = default;
71+
};
72+
73+
/// A no-op implementation of DeserializationNotificationHandlerBase. Intended
74+
/// to allow for users to implement only one of the relevant methods and have
75+
/// all other methods be no-ops.
76+
class DeserializationNotificationHandler
77+
: public DeserializationNotificationHandlerBase {
78+
public:
79+
/// Observe that we deserialized a function declaration.
80+
virtual void didDeserialize(ModuleDecl *mod, SILFunction *fn) override {}
81+
82+
/// Observe that we successfully deserialized a function body.
83+
virtual void didDeserializeFunctionBody(ModuleDecl *mod,
84+
SILFunction *fn) override {}
85+
86+
/// Observe that we successfully deserialized a witness table's entries.
87+
virtual void didDeserializeWitnessTableEntries(ModuleDecl *mod,
88+
SILWitnessTable *wt) override {
89+
}
90+
91+
/// Observe that we successfully deserialized a default witness table's
92+
/// entries.
93+
virtual void didDeserializeDefaultWitnessTableEntries(
94+
ModuleDecl *mod, SILDefaultWitnessTable *wt) override {}
95+
96+
/// Observe that we deserialized a global variable declaration.
97+
virtual void didDeserialize(ModuleDecl *mod,
98+
SILGlobalVariable *var) override {}
99+
100+
/// Observe that we deserialized a v-table declaration.
101+
virtual void didDeserialize(ModuleDecl *mod, SILVTable *vtable) override {}
102+
103+
/// Observe that we deserialized a witness-table declaration.
104+
virtual void didDeserialize(ModuleDecl *mod,
105+
SILWitnessTable *wtable) override {}
106+
107+
/// Observe that we deserialized a default witness-table declaration.
108+
virtual void didDeserialize(ModuleDecl *mod,
109+
SILDefaultWitnessTable *wtable) override {}
110+
111+
virtual StringRef getName() const = 0;
112+
113+
virtual ~DeserializationNotificationHandler() = default;
114+
};
115+
116+
/// A notification handler that only overrides didDeserializeFunctionBody and
117+
/// calls the passed in function pointer.
118+
class FunctionBodyDeserializationNotificationHandler final
119+
: public DeserializationNotificationHandler {
120+
public:
121+
using Handler = void (*)(ModuleDecl *, SILFunction *);
122+
123+
private:
124+
Handler handler;
125+
126+
public:
127+
FunctionBodyDeserializationNotificationHandler(Handler handler)
128+
: handler(handler) {}
129+
virtual ~FunctionBodyDeserializationNotificationHandler() {}
130+
131+
void didDeserializeFunctionBody(ModuleDecl *mod, SILFunction *fn) override {
132+
(*handler)(mod, fn);
133+
}
134+
135+
StringRef getName() const override {
136+
return "FunctionBodyDeserializationNotificationHandler";
137+
}
138+
};
139+
140+
/// A type that contains a set of unique DeserializationNotificationHandlers and
141+
/// implements DeserializationNotificationHandlerBase by iterating over the
142+
/// stored handlers and calling each handler's implementation.
143+
class DeserializationNotificationHandlerSet final
144+
: public DeserializationNotificationHandlerBase {
145+
public:
146+
using NotificationUniquePtr =
147+
std::unique_ptr<DeserializationNotificationHandler>;
148+
149+
private:
150+
/// A list of deserialization callbacks that update the SILModule and other
151+
/// parts of SIL as deserialization occurs.
152+
///
153+
/// We use 3 here since that is the most that will ever be used today in the
154+
/// compiler. If that changed, that number should be changed as well. The
155+
/// specific users are:
156+
///
157+
/// 1. SILModule's serialization callback.
158+
/// 2. SILPassManager notifications.
159+
/// 3. Access Enforcement Stripping notification.
160+
SmallVector<NotificationUniquePtr, 3> handlerSet;
161+
162+
public:
163+
DeserializationNotificationHandlerSet() = default;
164+
~DeserializationNotificationHandlerSet() = default;
165+
166+
bool erase(DeserializationNotificationHandler *handler) {
167+
auto iter = find_if(handlerSet, [&](const NotificationUniquePtr &h) {
168+
return handler == h.get();
169+
});
170+
if (iter == handlerSet.end())
171+
return false;
172+
handlerSet.erase(iter);
173+
return true;
174+
}
175+
176+
void add(NotificationUniquePtr &&handler) {
177+
// Since we store unique_ptrs and are accepting a movable rvalue here, we
178+
// should never have a case where we have a notification added twice. But
179+
// just to be careful, lets use an assert.
180+
assert(!count_if(handlerSet, [&](const NotificationUniquePtr &h) {
181+
return handler.get() == h.get();
182+
}) && "Two unique ptrs pointing at the same memory?!");
183+
handlerSet.emplace_back(std::move(handler));
184+
}
185+
186+
static DeserializationNotificationHandler *
187+
getUnderlyingHandler(const NotificationUniquePtr &h) {
188+
return h.get();
189+
}
190+
191+
/// An iterator into the notification set that returns a bare
192+
/// 'DeserializationNotificationHandler *' projected from one of the
193+
/// underlying std::unique_ptr<DeserializationNotificationHandler>.
194+
using iterator = llvm::mapped_iterator<
195+
decltype(handlerSet)::const_iterator,
196+
decltype(&DeserializationNotificationHandlerSet::getUnderlyingHandler)>;
197+
using range = llvm::iterator_range<iterator>;
198+
199+
/// Returns an iterator to the first element of the handler set.
200+
///
201+
/// NOTE: This iterator has a value_type of
202+
/// 'DeserializationNotificationHandler'.
203+
iterator begin() const {
204+
auto *fptr = &DeserializationNotificationHandlerSet::getUnderlyingHandler;
205+
return llvm::map_iterator(handlerSet.begin(), fptr);
206+
}
207+
208+
/// Returns an iterator to the end of the handler set.
209+
///
210+
/// NOTE: This iterator has a value_type of
211+
/// 'DeserializationNotificationHandler'.
212+
iterator end() const {
213+
auto *fptr = &DeserializationNotificationHandlerSet::getUnderlyingHandler;
214+
return llvm::map_iterator(handlerSet.end(), fptr);
215+
}
216+
217+
/// Returns a range that iterates over bare pointers projected from the
218+
/// internal owned memory pointers in the handlerSet.
219+
///
220+
/// NOTE: The underlying iterator value_type here is
221+
/// 'DeserializationNotificationHandler *'.
222+
auto getRange() const -> range { return llvm::make_range(begin(), end()); }
223+
224+
//===--------------------------------------------------------------------===//
225+
// DeserializationNotificationHandler implementation via chaining to the
226+
// handlers we contain.
227+
//===--------------------------------------------------------------------===//
228+
229+
void didDeserialize(ModuleDecl *mod, SILFunction *fn) override;
230+
void didDeserializeFunctionBody(ModuleDecl *mod, SILFunction *fn) override;
231+
void didDeserializeWitnessTableEntries(ModuleDecl *mod,
232+
SILWitnessTable *wt) override;
233+
void
234+
didDeserializeDefaultWitnessTableEntries(ModuleDecl *mod,
235+
SILDefaultWitnessTable *wt) override;
236+
void didDeserialize(ModuleDecl *mod, SILGlobalVariable *var) override;
237+
void didDeserialize(ModuleDecl *mod, SILVTable *vtable) override;
238+
void didDeserialize(ModuleDecl *mod, SILWitnessTable *wtable) override;
239+
void didDeserialize(ModuleDecl *mod,
240+
SILDefaultWitnessTable *wtable) override;
241+
};
19242

20243
/// A protocol (or interface) for handling value deletion notifications.
21244
///
@@ -24,7 +247,6 @@ class SILNode;
24247
/// analysis that need to invalidate data structures that contain pointers.
25248
/// This is similar to LLVM's ValueHandle.
26249
struct DeleteNotificationHandler {
27-
28250
DeleteNotificationHandler() { }
29251
virtual ~DeleteNotificationHandler() {}
30252

@@ -38,7 +260,6 @@ struct DeleteNotificationHandler {
38260
virtual bool needsNotifications() { return false; }
39261
};
40262

41-
} // end swift namespace
263+
} // namespace swift
42264

43265
#endif
44-

include/swift/SIL/SILModule.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,8 @@ class SILModule {
226226
/// The stage of processing this module is at.
227227
SILStage Stage;
228228

229-
/// The callback used by the SILLoader.
230-
std::unique_ptr<SerializationCallback> Callback;
231-
232-
// Callbacks registered by the SIL optimizer to run on each deserialized
233-
// function body. This is intentionally a stateless type because the
234-
// ModuleDecl and SILFunction should be sufficient context.
235-
using SILFunctionBodyCallback = void (*)(ModuleDecl *, SILFunction *F);
236-
SmallVector<SILFunctionBodyCallback, 0> DeserializationCallbacks;
229+
/// The set of deserialization notification handlers.
230+
DeserializationNotificationHandlerSet deserializationNotificationHandlers;
237231

238232
/// The SILLoader used when linking functions into this module.
239233
///
@@ -283,10 +277,19 @@ class SILModule {
283277
~SILModule();
284278

285279
/// Add a callback for each newly deserialized SIL function body.
286-
void registerDeserializationCallback(SILFunctionBodyCallback callBack);
280+
void registerDeserializationNotificationHandler(
281+
std::unique_ptr<DeserializationNotificationHandler> &&handler);
282+
283+
/// Return the set of registered deserialization callbacks.
284+
DeserializationNotificationHandlerSet::range
285+
getDeserializationHandlers() const {
286+
return deserializationNotificationHandlers.getRange();
287+
}
287288

288-
/// Return set of registered deserialization callbacks.
289-
ArrayRef<SILFunctionBodyCallback> getDeserializationCallbacks();
289+
void removeDeserializationNotificationHandler(
290+
DeserializationNotificationHandler *handler) {
291+
deserializationNotificationHandlers.erase(handler);
292+
}
290293

291294
/// Add a delete notification handler \p Handler to the module context.
292295
void registerDeleteNotificationHandler(DeleteNotificationHandler* Handler);

include/swift/Serialization/SerializedSILLoader.h

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "swift/AST/Decl.h"
1717
#include "swift/AST/Identifier.h"
18+
#include "swift/SIL/Notifications.h"
1819
#include "swift/SIL/SILDeclRef.h"
1920
#include "swift/SIL/SILLinkage.h"
2021
#include <memory>
@@ -36,56 +37,22 @@ class SILDefaultWitnessTable;
3637
/// in ASTContext. It provides lookupSILFunction that will perform lookup
3738
/// on each SILDeserializer.
3839
class SerializedSILLoader {
39-
public:
40-
class Callback {
41-
public:
42-
/// Observe that we deserialized a function declaration.
43-
virtual void didDeserialize(ModuleDecl *M, SILFunction *fn) {}
44-
45-
/// Observe that we successfully deserialized a function body.
46-
virtual void didDeserializeFunctionBody(ModuleDecl *M, SILFunction *fn) {}
47-
48-
/// Observe that we successfully deserialized a witness table's entries.
49-
virtual void didDeserializeWitnessTableEntries(ModuleDecl *M,
50-
SILWitnessTable *wt) {}
51-
52-
/// Observe that we successfully deserialized a default witness table's
53-
/// entries.
54-
virtual void didDeserializeDefaultWitnessTableEntries(ModuleDecl *M,
55-
SILDefaultWitnessTable *wt) {}
56-
57-
/// Observe that we deserialized a global variable declaration.
58-
virtual void didDeserialize(ModuleDecl *M, SILGlobalVariable *var) {}
59-
60-
/// Observe that we deserialized a v-table declaration.
61-
virtual void didDeserialize(ModuleDecl *M, SILVTable *vtable) {}
62-
63-
/// Observe that we deserialized a witness-table declaration.
64-
virtual void didDeserialize(ModuleDecl *M, SILWitnessTable *wtable) {}
65-
66-
/// Observe that we deserialized a default witness-table declaration.
67-
virtual void didDeserialize(ModuleDecl *M, SILDefaultWitnessTable *wtable) {}
68-
69-
virtual ~Callback() = default;
70-
private:
71-
virtual void _anchor();
72-
};
73-
7440
private:
75-
std::vector<std::unique_ptr<SILDeserializer> > LoadedSILSections;
41+
std::vector<std::unique_ptr<SILDeserializer>> LoadedSILSections;
7642

77-
explicit SerializedSILLoader(ASTContext &ctx, SILModule *SILMod,
78-
Callback *callback);
43+
explicit SerializedSILLoader(
44+
ASTContext &ctx, SILModule *SILMod,
45+
DeserializationNotificationHandlerSet *callbacks);
7946

8047
public:
8148
/// Create a new loader.
8249
///
83-
/// \param callback - not owned by the loader
84-
static std::unique_ptr<SerializedSILLoader> create(ASTContext &ctx,
85-
SILModule *SILMod,
86-
Callback *callback) {
50+
/// \param callbacks - not owned by the loader
51+
static std::unique_ptr<SerializedSILLoader>
52+
create(ASTContext &ctx, SILModule *SILMod,
53+
DeserializationNotificationHandlerSet *callbacks) {
8754
return std::unique_ptr<SerializedSILLoader>(
88-
new SerializedSILLoader(ctx, SILMod, callback));
55+
new SerializedSILLoader(ctx, SILMod, callbacks));
8956
}
9057
~SerializedSILLoader();
9158

lib/SIL/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_swift_library(swiftSIL STATIC
1010
Linker.cpp
1111
LinearLifetimeChecker.cpp
1212
LoopInfo.cpp
13+
Notifications.cpp
1314
OptimizationRemark.cpp
1415
PrettyStackTrace.cpp
1516
Projection.cpp

0 commit comments

Comments
 (0)