Skip to content

Commit 1c3073b

Browse files
committed
[DefaultOverrides] SILGen.
Emit tables for open members of open classes.
1 parent cc4c458 commit 1c3073b

File tree

3 files changed

+556
-0
lines changed

3 files changed

+556
-0
lines changed

lib/SILGen/SILGen.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
389389
/// Emit the default witness table for a resilient protocol.
390390
void emitDefaultWitnessTable(ProtocolDecl *protocol);
391391

392+
void emitDefaultOverrideTable(ClassDecl *decl);
393+
394+
SILFunction *emitDefaultOverride(SILDeclRef replacement, SILDeclRef original);
395+
392396
/// Emit the self-conformance witness table for a protocol.
393397
void emitSelfConformanceWitnessTable(ProtocolDecl *protocol);
394398

lib/SILGen/SILGenType.cpp

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "swift/SIL/FormalLinkage.h"
3535
#include "swift/SIL/PrettyStackTrace.h"
3636
#include "swift/SIL/SILArgument.h"
37+
#include "swift/SIL/SILDefaultOverrideTable.h"
3738
#include "swift/SIL/SILVTableVisitor.h"
3839
#include "swift/SIL/SILWitnessVisitor.h"
3940
#include "swift/SIL/TypeLowering.h"
@@ -1146,6 +1147,225 @@ void SILGenModule::emitDefaultWitnessTable(ProtocolDecl *protocol) {
11461147
defaultWitnesses->convertToDefinition(builder.DefaultWitnesses);
11471148
}
11481149

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+
11491369
void SILGenModule::emitNonCopyableTypeDeinitTable(NominalTypeDecl *nom) {
11501370
auto *dd = nom->getValueTypeDestructor();
11511371
if (!dd)
@@ -1189,6 +1409,11 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
11891409
SILGenVTable genVTable(SGM, theClass);
11901410
genVTable.emitVTable();
11911411
}
1412+
if (!theClass->hasClangNode() && theClass->isResilient()) {
1413+
auto *sourceFile = theClass->getParentSourceFile();
1414+
if (!sourceFile || sourceFile->Kind != SourceFileKind::Interface)
1415+
SGM.emitDefaultOverrideTable(theClass);
1416+
}
11921417
}
11931418

11941419
// If this is a nominal type that is move only, emit a deinit table for it.

0 commit comments

Comments
 (0)