-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathLinker.h
166 lines (142 loc) · 5.91 KB
/
Linker.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
//===--- Linker.h -----------------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_LINKER_H
#define SWIFT_SIL_LINKER_H
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SIL/SILModule.h"
#include <functional>
namespace swift {
/// Visits the call graph and makes sure that all required functions (according
/// to the linking `Mode`) are de-serialized and the `isSerialized` flag is set
/// correctly.
///
/// If the Mode is LinkNormal, just de-serialize the bare minimum of what's
/// required for a non-optimized compilation. That are all referenced shared
/// functions, because shared functions must have a body.
///
/// If the Mode is LinkAll, de-serialize the maximum amount of functions - for
/// optimized compilation.
///
/// Also make sure that shared functions which are referenced from "IsSerialized"
/// functions also have the "IsSerialized" flag set.
/// Usually this already is enforced by SILGen and all passes which create new
/// functions.
/// Only in case a de-serialized function references a shared function which
/// already exists in the module as "IsNotSerialized", it's required to explicitly
/// set the "IsSerialized" flag.
///
/// Example:
///
/// Before de-serialization:
/// \code
/// sil @foo {
/// function_ref @publicFuncInOtherModule
/// function_ref @specializedFunction
/// }
/// sil shared @specializedFunction { // IsNotSerialized
/// function_ref @otherSpecializedFunction
/// }
/// sil shared @otherSpecializedFunction { // IsNotSerialized
/// }
/// \endcode
///
/// After de-serialization:
/// \code
/// sil @foo {
/// function_ref @publicFuncInOtherModule
/// function_ref @specializedFunction
/// }
/// sil public_external [serialized] @publicFuncInOtherModule {
/// function_ref @specializedFunction
/// }
/// // Need to be changed to "IsSerialized"
/// sil shared [serialized] @specializedFunction {
/// function_ref @otherSpecializedFunction
/// }
/// sil shared [serialized] @otherSpecializedFunction {
/// }
/// \endcode
///
class SILLinkerVisitor : public SILInstructionVisitor<SILLinkerVisitor, void> {
using LinkingMode = SILModule::LinkingMode;
/// The SILModule that we are loading from.
SILModule &Mod;
/// Break cycles visiting recursive protocol conformances.
llvm::DenseSet<ProtocolConformance *> VisitedConformances;
/// Worklist of SILFunctions we are processing.
llvm::SmallVector<SILFunction *, 128> Worklist;
llvm::SmallVector<SILFunction *, 32> toVerify;
/// The current linking mode.
LinkingMode Mode;
/// Whether any functions were deserialized.
bool Changed;
bool hasError = false;
public:
SILLinkerVisitor(SILModule &M, SILModule::LinkingMode LinkingMode)
: Mod(M), Worklist(), Mode(LinkingMode), Changed(false) {}
/// Process F, recursively deserializing any thing F may reference.
/// Returns true if any deserialization was performed.
bool processFunction(SILFunction *F);
/// Process the witnesstable of \p conformanceRef.
/// Returns true if any deserialization was performed.
bool processConformance(ProtocolConformanceRef conformanceRef);
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
/// transitively references.
///
/// This method assumes that the caller made sure that no vtable existed in
/// Mod.
SILVTable *processClassDecl(const ClassDecl *C);
/// We do not want to visit callee functions if we just have a value base.
void visitSILInstruction(SILInstruction *I) { }
void visitApplyInst(ApplyInst *AI);
void visitTryApplyInst(TryApplyInst *TAI);
void visitPartialApplyInst(PartialApplyInst *PAI);
void visitFunctionRefInst(FunctionRefInst *FRI);
void visitDynamicFunctionRefInst(DynamicFunctionRefInst *FRI);
void visitPreviousDynamicFunctionRefInst(PreviousDynamicFunctionRefInst *FRI);
void visitProtocolConformance(ProtocolConformanceRef C,
bool referencedFromInitExistential);
void visitApplySubstitutions(SubstitutionMap subs);
void visitWitnessMethodInst(WitnessMethodInst *WMI) {
visitProtocolConformance(WMI->getConformance(), false);
}
void visitInitExistentialAddrInst(InitExistentialAddrInst *IEI);
void visitInitExistentialRefInst(InitExistentialRefInst *IERI);
void visitBuiltinInst(BuiltinInst *bi);
void visitAllocRefInst(AllocRefInst *ARI);
void visitAllocRefDynamicInst(AllocRefDynamicInst *ARI);
void visitMetatypeInst(MetatypeInst *MI);
void visitGlobalAddrInst(GlobalAddrInst *i);
private:
/// Cause a function to be deserialized, and visit all other functions
/// referenced from this function according to the linking mode.
void deserializeAndPushToWorklist(SILFunction *F);
/// Consider a function for deserialization if the current linking mode
/// requires it.
///
/// If `callerSerializedKind` is IsSerialized, then all shared
/// functions which are referenced from `F` are set to be serialized.
void maybeAddFunctionToWorklist(SILFunction *F,
SerializedKind_t callerSerializedKind,
SILFunction *caller = nullptr);
/// Is the current mode link all? Link all implies we should try and link
/// everything, not just transparent/shared functions.
bool isLinkAll() const {
return Mode == LinkingMode::LinkAll || Mod.getOptions().EmbeddedSwift;
}
void linkInVTable(ClassDecl *D);
// Main loop of the visitor. Called by one of the other *visit* methods.
void process();
};
} // end namespace swift
#endif