|
34 | 34 | #include "swift/SIL/FormalLinkage.h"
|
35 | 35 | #include "swift/SIL/PrettyStackTrace.h"
|
36 | 36 | #include "swift/SIL/SILArgument.h"
|
| 37 | +#include "swift/SIL/SILDefaultOverrideTable.h" |
37 | 38 | #include "swift/SIL/SILVTableVisitor.h"
|
38 | 39 | #include "swift/SIL/SILWitnessVisitor.h"
|
39 | 40 | #include "swift/SIL/TypeLowering.h"
|
@@ -1146,6 +1147,225 @@ void SILGenModule::emitDefaultWitnessTable(ProtocolDecl *protocol) {
|
1146 | 1147 | defaultWitnesses->convertToDefinition(builder.DefaultWitnesses);
|
1147 | 1148 | }
|
1148 | 1149 |
|
| 1150 | +namespace { |
| 1151 | + |
| 1152 | +std::optional<AccessorKind> |
| 1153 | +originalAccessorKindForReplacementKind(AccessorKind kind) { |
| 1154 | + switch (kind) { |
| 1155 | + case AccessorKind::Read2: |
| 1156 | + return {AccessorKind::Read}; |
| 1157 | + case AccessorKind::Modify2: |
| 1158 | + return {AccessorKind::Modify}; |
| 1159 | + case AccessorKind::Get: |
| 1160 | + case AccessorKind::DistributedGet: |
| 1161 | + case AccessorKind::Set: |
| 1162 | + case AccessorKind::Read: |
| 1163 | + case AccessorKind::Modify: |
| 1164 | + case AccessorKind::WillSet: |
| 1165 | + case AccessorKind::DidSet: |
| 1166 | + case AccessorKind::Address: |
| 1167 | + case AccessorKind::MutableAddress: |
| 1168 | + case AccessorKind::Init: |
| 1169 | + return std::nullopt; |
| 1170 | + } |
| 1171 | +} |
| 1172 | + |
| 1173 | +/// Emit a default witness table for a resilient protocol definition. |
| 1174 | +class SILGenDefaultOverrideTable |
| 1175 | + : public SILGenVTableBase<SILGenDefaultOverrideTable> { |
| 1176 | + using super = SILGenVTableBase<SILGenDefaultOverrideTable>; |
| 1177 | + |
| 1178 | +public: |
| 1179 | + SILLinkage linkage; |
| 1180 | + SILGenDefaultOverrideTable(SILGenModule &SGM, ClassDecl *decl, |
| 1181 | + SILLinkage linkage) |
| 1182 | + : super(SGM, decl), linkage(linkage) {} |
| 1183 | + |
| 1184 | + std::optional<SILDefaultOverrideTable::Entry> |
| 1185 | + entryForMethod(VTableMethod method) { |
| 1186 | + // Determine whether `method` semantically "replaces" some other member (in |
| 1187 | + // the sense that calls that previously resolved to that other member will |
| 1188 | + // now resolve to that new member). If it does, produce a default override |
| 1189 | + // table entry which describes that replacement, including a thunk (to be |
| 1190 | + // installed at runtime) in subclasses which overrode only that other |
| 1191 | + // replaced member. |
| 1192 | + auto declRef = method.first; |
| 1193 | + auto *decl = declRef.getAbstractFunctionDecl(); |
| 1194 | + if (decl->getEffectiveAccess() != AccessLevel::Open) { |
| 1195 | + // Only methods which can be overridden in different resilience domains |
| 1196 | + // need an entry. |
| 1197 | + return std::nullopt; |
| 1198 | + } |
| 1199 | + // Currently, only accessors can be replacements. |
| 1200 | + auto *accessor = dyn_cast_or_null<AccessorDecl>(decl); |
| 1201 | + if (!accessor) { |
| 1202 | + return std::nullopt; |
| 1203 | + } |
| 1204 | + // Specifically, read2 can replace _read and modify2 can replace _modify. |
| 1205 | + auto originalKind = |
| 1206 | + originalAccessorKindForReplacementKind(accessor->getAccessorKind()); |
| 1207 | + if (!originalKind) { |
| 1208 | + return std::nullopt; |
| 1209 | + } |
| 1210 | + auto *originalDecl = accessor->getStorage()->getAccessor(*originalKind); |
| 1211 | + if (!originalDecl) { |
| 1212 | + return std::nullopt; |
| 1213 | + } |
| 1214 | + auto original = SILDeclRef(originalDecl); |
| 1215 | + auto *impl = SGM.emitDefaultOverride(declRef, original); |
| 1216 | + return {SILDefaultOverrideTable::Entry{declRef, original, impl}}; |
| 1217 | + } |
| 1218 | + |
| 1219 | + void emitTable() { |
| 1220 | + PrettyStackTraceDecl("silgen emitDefaultOverrideTable", theClass); |
| 1221 | + |
| 1222 | + if (!theClass->isResilient()) { |
| 1223 | + // Only resilient classes need such tables. |
| 1224 | + return; |
| 1225 | + } |
| 1226 | + if (theClass->getEffectiveAccess() != AccessLevel::Open) { |
| 1227 | + // Only classes whose methods could be overridden in different resilience |
| 1228 | + // domains need an entry. |
| 1229 | + return; |
| 1230 | + } |
| 1231 | + |
| 1232 | + collectMethods(); |
| 1233 | + |
| 1234 | + SmallVector<SILDefaultOverrideTable::Entry, 8> entries; |
| 1235 | + |
| 1236 | + for (auto method : vtableMethods) { |
| 1237 | + auto entry = entryForMethod(method); |
| 1238 | + if (!entry) { |
| 1239 | + continue; |
| 1240 | + } |
| 1241 | + entries.push_back(*entry); |
| 1242 | + } |
| 1243 | + |
| 1244 | + if (entries.size() == 0) { |
| 1245 | + // Don't emit empty tables. |
| 1246 | + return; |
| 1247 | + } |
| 1248 | + |
| 1249 | + SGM.M.createDefaultOverrideTableDefinition(theClass, linkage, entries); |
| 1250 | + } |
| 1251 | +}; |
| 1252 | + |
| 1253 | +} // end anonymous namespace |
| 1254 | + |
| 1255 | +void SILGenModule::emitDefaultOverrideTable(ClassDecl *decl) { |
| 1256 | + SILLinkage linkage = getSILLinkage(getDeclLinkage(decl), ForDefinition); |
| 1257 | + |
| 1258 | + SILGenDefaultOverrideTable builder(*this, decl, linkage); |
| 1259 | + builder.emitTable(); |
| 1260 | +} |
| 1261 | + |
| 1262 | +SILFunction *SILGenModule::emitDefaultOverride(SILDeclRef replacement, |
| 1263 | + SILDeclRef original) { |
| 1264 | + SILGenFunctionBuilder builder(*this); |
| 1265 | + // Add the "default override of" suffix. |
| 1266 | + auto name = replacement.mangle() + "Twd"; |
| 1267 | + auto replacementTy = |
| 1268 | + Types.getConstantInfo(TypeExpansionContext::minimal(), replacement) |
| 1269 | + .SILFnType; |
| 1270 | + auto loc = replacement.getAsRegularLocation(); |
| 1271 | + auto *function = builder.getOrCreateFunction( |
| 1272 | + loc, name, SILLinkage::Shared, replacementTy, IsBare, IsNotTransparent, |
| 1273 | + IsSerialized, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible, |
| 1274 | + ProfileCounter(), IsNotThunk); |
| 1275 | + |
| 1276 | + if (!function->empty()) |
| 1277 | + return function; |
| 1278 | + |
| 1279 | + // A shim from yield_once_2 (replacement) to yield_once (original). |
| 1280 | + // sil @shim : $@convention(method) @yield_once_2 (As...) -> (@yields Ys...) { |
| 1281 | + // entry(%as... : $As...): |
| 1282 | + // %method = class_method |
| 1283 | + // (%ys... : $Ys..., %token) = begin_apply %method(%as...) |
| 1284 | + // : $@convention(method) @yield_once (As...) -> (@yields Ys...) |
| 1285 | + // yield %ys : $Ys..., normal normal_block, error error_block |
| 1286 | + // normal_block: |
| 1287 | + // %retval = end_apply %token |
| 1288 | + // return %retval : $() |
| 1289 | + // error_block: |
| 1290 | + // abort_apply %token |
| 1291 | + // unwind |
| 1292 | + // } |
| 1293 | + |
| 1294 | + auto sig = replacementTy->getSubstGenericSignature(); |
| 1295 | + auto *env = sig.getGenericEnvironment(); |
| 1296 | + auto subs = env ? env->getForwardingSubstitutionMap() : SubstitutionMap(); |
| 1297 | + function->setGenericEnvironment(env); |
| 1298 | + SILGenFunction SGF(*this, *function, SwiftModule); |
| 1299 | + SmallVector<ManagedValue, 4> params; |
| 1300 | + SmallVector<ManagedValue, 4> indirectResults; |
| 1301 | + SmallVector<ManagedValue, 4> indirectErrors; |
| 1302 | + SGF.collectThunkParams(replacement.getDecl(), params, &indirectResults, |
| 1303 | + &indirectErrors); |
| 1304 | + |
| 1305 | + auto self = params.back(); |
| 1306 | + |
| 1307 | + auto originalTy = |
| 1308 | + Types.getConstantInfo(TypeExpansionContext::minimal(), original) |
| 1309 | + .SILFnType; |
| 1310 | + auto originalFn = |
| 1311 | + SGF.emitClassMethodRef(loc, self.getValue(), original, originalTy); |
| 1312 | + auto originalConvention = SILFunctionConventions(originalTy, M); |
| 1313 | + assert(indirectErrors.size() == 0 && |
| 1314 | + "coroutine accessor with indirect error!?"); |
| 1315 | + SmallVector<SILValue> args; |
| 1316 | + for (auto result : indirectResults) { |
| 1317 | + args.push_back(result.forward(SGF)); |
| 1318 | + } |
| 1319 | + for (auto param : params) { |
| 1320 | + args.push_back(param.forward(SGF)); |
| 1321 | + } |
| 1322 | + auto *bai = SGF.B.createBeginApply(loc, originalFn, subs, args); |
| 1323 | + auto *token = bai->getTokenResult(); |
| 1324 | + auto yieldedValues = bai->getYieldedValues(); |
| 1325 | + auto *normalBlock = function->createBasicBlockAfter(SGF.B.getInsertionBB()); |
| 1326 | + auto *errorBlock = function->createBasicBlockAfter(normalBlock); |
| 1327 | + SmallVector<SILValue> yields; |
| 1328 | + for (auto yielded : yieldedValues) { |
| 1329 | + yields.push_back(yielded); |
| 1330 | + } |
| 1331 | + SGF.B.createYield(loc, yields, normalBlock, errorBlock); |
| 1332 | + |
| 1333 | + SGF.B.setInsertionPoint(normalBlock); |
| 1334 | + llvm::SmallVector<TupleTypeElt> directResultTypes; |
| 1335 | + |
| 1336 | + for (auto result : originalConvention.getDirectSILResults()) { |
| 1337 | + auto ty = originalConvention.getSILType( |
| 1338 | + result, function->getTypeExpansionContext()); |
| 1339 | + ty = function->mapTypeIntoContext(ty); |
| 1340 | + directResultTypes.push_back(ty.getASTType()); |
| 1341 | + } |
| 1342 | + SILType resultTy; |
| 1343 | + switch (directResultTypes.size()) { |
| 1344 | + case 0: |
| 1345 | + resultTy = SILType::getEmptyTupleType(getASTContext()); |
| 1346 | + break; |
| 1347 | + case 1: |
| 1348 | + resultTy = SILType::getPrimitiveObjectType( |
| 1349 | + directResultTypes.front().getType()->getCanonicalType()); |
| 1350 | + break; |
| 1351 | + default: { |
| 1352 | + ASSERT(directResultTypes.size() > 1); |
| 1353 | + auto tupleTy = |
| 1354 | + TupleType::get(directResultTypes, getASTContext())->getCanonicalType(); |
| 1355 | + resultTy = SILType::getPrimitiveObjectType(tupleTy); |
| 1356 | + break; |
| 1357 | + } |
| 1358 | + } |
| 1359 | + SGF.B.createEndApply(loc, token, resultTy); |
| 1360 | + auto *retval = SGF.B.createTuple(loc, {}); |
| 1361 | + SGF.B.createReturn(loc, retval); |
| 1362 | + |
| 1363 | + SGF.B.setInsertionPoint(errorBlock); |
| 1364 | + SGF.B.createAbortApply(loc, token); |
| 1365 | + SGF.B.createUnwind(loc); |
| 1366 | + return function; |
| 1367 | +} |
| 1368 | + |
1149 | 1369 | void SILGenModule::emitNonCopyableTypeDeinitTable(NominalTypeDecl *nom) {
|
1150 | 1370 | auto *dd = nom->getValueTypeDestructor();
|
1151 | 1371 | if (!dd)
|
@@ -1189,6 +1409,11 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
|
1189 | 1409 | SILGenVTable genVTable(SGM, theClass);
|
1190 | 1410 | genVTable.emitVTable();
|
1191 | 1411 | }
|
| 1412 | + if (!theClass->hasClangNode() && theClass->isResilient()) { |
| 1413 | + auto *sourceFile = theClass->getParentSourceFile(); |
| 1414 | + if (!sourceFile || sourceFile->Kind != SourceFileKind::Interface) |
| 1415 | + SGM.emitDefaultOverrideTable(theClass); |
| 1416 | + } |
1192 | 1417 | }
|
1193 | 1418 |
|
1194 | 1419 | // If this is a nominal type that is move only, emit a deinit table for it.
|
|
0 commit comments