@@ -459,6 +459,13 @@ namespace {
459
459
// / corresponds to `self`.
460
460
void injectActorHops ();
461
461
462
+ // / Injects `self.$storage = .init(memberwise: $Storage(...))`
463
+ // / assignment instructions into the function after each point
464
+ // / where `_storage` becomes fully initialized via `assign_by_wrapper`.
465
+ // / This is only necessary only for user-defined initializers of a
466
+ // / type wrapped types.
467
+ void injectTypeWrapperStorageInitalization ();
468
+
462
469
void emitSelfConsumedDiagnostic (SILInstruction *Inst);
463
470
464
471
LiveOutBlockState &getBlockInfo (SILBasicBlock *BB) {
@@ -1070,6 +1077,284 @@ void LifetimeChecker::injectActorHops() {
1070
1077
injectExecutorHopAfter (point);
1071
1078
}
1072
1079
1080
+ void LifetimeChecker::injectTypeWrapperStorageInitalization () {
1081
+ auto *storageVar = TheMemory.getAsTypeWrapperLocalStorageVar ();
1082
+ if (!storageVar)
1083
+ return ;
1084
+
1085
+ SmallVector<SILInstruction *> points;
1086
+ findFullInitializationPoints (points);
1087
+
1088
+ // `_storage` has not been initialized at all.
1089
+ if (points.empty ())
1090
+ return ;
1091
+
1092
+ auto *ctor = cast<ConstructorDecl>(storageVar->getDeclContext ()->getAsDecl ());
1093
+ auto *parentType = ctor->getDeclContext ()->getSelfNominalTypeDecl ();
1094
+ auto *storageDecl = parentType->getTypeWrapperStorageDecl ();
1095
+
1096
+ for (auto *point : points) {
1097
+ SILBuilderWithScope::insertAfter (point, [&](SILBuilder &b) {
1098
+ SILLocation loc = SILLocation::invalid ().asAutoGenerated ();
1099
+
1100
+ SmallVector<SILValue, 4 > allocations;
1101
+
1102
+ auto allocStack = [&](SILType type) -> SILValue {
1103
+ auto value = b.createAllocStack (loc, type);
1104
+ allocations.push_back (value);
1105
+ return value;
1106
+ };
1107
+
1108
+ auto createInitRef = [&](ConstructorDecl *ctor) -> SILValue {
1109
+ auto *init = F.getModule ().lookUpFunction (SILDeclRef (ctor));
1110
+ assert (init);
1111
+ return b.createFunctionRef (loc, init);
1112
+ };
1113
+
1114
+ // The instance type of $Storage declaration.
1115
+ auto storageType = F.getLoweredType (
1116
+ ctor->mapTypeIntoContext (storageDecl->getDeclaredInterfaceType ()));
1117
+
1118
+ // Argument value to use in call to <TypeWrapper>.init(memberwise:)
1119
+ SILValue storageObj = allocStack (storageType);
1120
+
1121
+ // let storageObj = $Storage(<destructured _storage tuple>)
1122
+ {
1123
+ SILValue localStorageVar = TheMemory.getUninitializedValue ();
1124
+
1125
+ SmallVector<SILValue> storageInitArgs;
1126
+
1127
+ SILValue storageInitRef;
1128
+ if (auto *memberwiseInit = storageDecl->getMemberwiseInitializer ()) {
1129
+ storageInitRef = createInitRef (memberwiseInit);
1130
+ } else {
1131
+ assert (storageDecl->hasDefaultInitializer ());
1132
+ storageInitRef = createInitRef (storageDecl->getDefaultInitializer ());
1133
+ }
1134
+
1135
+ CanSILFunctionType storageInitTy =
1136
+ storageInitRef->getType ().castTo <SILFunctionType>();
1137
+ SILFunctionConventions convention (storageInitTy, F.getModule ());
1138
+
1139
+ // If `.init` produces result indirectly, let's load it
1140
+ // into the prepared buffer.
1141
+ if (convention.hasIndirectSILResults ()) {
1142
+ assert (convention.getNumIndirectSILResults () == 1 );
1143
+ storageInitArgs.push_back (storageObj);
1144
+ }
1145
+
1146
+ // Prepare arguments for $Storage.init(...) call. `_storage`
1147
+ // tuple needs to be flattened and its elements have to be
1148
+ // either copied or loaded based on a particular argument convention.
1149
+ {
1150
+ auto localStorageRef =
1151
+ b.createBeginAccess (loc, localStorageVar, SILAccessKind::Read,
1152
+ SILAccessEnforcement::Unsafe,
1153
+ /* noNestedConflict=*/ false ,
1154
+ /* fromBuiltin=*/ false );
1155
+
1156
+ // There could be only one indirect result her - $Storage,
1157
+ // which is also verified above, actual arguments start
1158
+ // at 1 in such case.
1159
+ unsigned argIdx = convention.getNumIndirectSILResults ();
1160
+
1161
+ std::function<void (SILValue, SmallVectorImpl<SILValue> &)>
1162
+ prepareArguments =
1163
+ [&](SILValue val, SmallVectorImpl<SILValue> &results) {
1164
+ // Destructure the tuple into individual elements recursively.
1165
+ if (auto tupleType = val->getType ().getAs <TupleType>()) {
1166
+ for (unsigned i = 0 , n = tupleType->getNumElements ();
1167
+ i != n; ++i) {
1168
+ SILValue elt = b.createTupleElementAddr (loc, val, i);
1169
+ prepareArguments (elt, results);
1170
+ }
1171
+ return ;
1172
+ }
1173
+
1174
+ switch (convention.getSILArgumentConvention (argIdx)) {
1175
+ case SILArgumentConvention::Indirect_In:
1176
+ case SILArgumentConvention::Indirect_In_Constant: {
1177
+ // The only way to load opaque type is to allocate a temporary
1178
+ // variable on the stack for it and initialize from the element
1179
+ // address.
1180
+ SILValue arg = allocStack (val->getType ());
1181
+ b.createCopyAddr (loc, val, arg, IsNotTake, IsInitialization);
1182
+ results.push_back (arg);
1183
+ break ;
1184
+ }
1185
+
1186
+ case SILArgumentConvention::Indirect_In_Guaranteed:
1187
+ // The argument is +0, so we can use the address of the
1188
+ // element as an argument.
1189
+ results.push_back (val);
1190
+ break ;
1191
+
1192
+ case SILArgumentConvention::Direct_Owned: {
1193
+ // Copy the value out at +1.
1194
+ results.push_back (b.createTrivialLoadOr (
1195
+ loc, val, LoadOwnershipQualifier::Copy));
1196
+ break ;
1197
+ }
1198
+
1199
+ case SILArgumentConvention::Direct_Unowned:
1200
+ case SILArgumentConvention::Direct_Guaranteed: {
1201
+ results.push_back (b.createTrivialLoadOr (
1202
+ loc, val, LoadOwnershipQualifier::Take));
1203
+ break ;
1204
+ }
1205
+
1206
+ case SILArgumentConvention::Indirect_Out:
1207
+ llvm_unreachable (" indirect result is handled separately" );
1208
+
1209
+ case SILArgumentConvention::Indirect_Inout:
1210
+ case SILArgumentConvention::Indirect_InoutAliasable:
1211
+ llvm_unreachable (" inout arguments are not supported by $Storage." );
1212
+ }
1213
+
1214
+ ++argIdx;
1215
+ };
1216
+
1217
+ prepareArguments (localStorageRef, storageInitArgs);
1218
+
1219
+ b.createEndAccess (loc, localStorageRef, /* abort=*/ false );
1220
+ }
1221
+
1222
+ // append $Storage.Type as the last argument to $Storage.init()
1223
+ {
1224
+ auto storageMetatypeType = F.getLoweredType (
1225
+ ctor->mapTypeIntoContext (storageDecl->getInterfaceType ()));
1226
+ storageInitArgs.push_back (b.createMetatype (loc, storageMetatypeType));
1227
+ }
1228
+
1229
+ SubstitutionMap storageInitSubs;
1230
+ // Generic signature of $Storage is appropriate because
1231
+ // the call is to either memberwise or default initializer
1232
+ // which cannot introduce any additional generic parameters.
1233
+ if (auto genericSig = storageDecl->getGenericSignature ()) {
1234
+ storageInitSubs = SubstitutionMap::get (
1235
+ genericSig,
1236
+ [&](SubstitutableType *type) {
1237
+ return ctor->mapTypeIntoContext (type);
1238
+ },
1239
+ LookUpConformanceInModule (
1240
+ ctor->getDeclContext ()->getParentModule ()));
1241
+ }
1242
+
1243
+ // <storage> = $Storage.init(<flattened `_storage` elements>)
1244
+ auto storageInitResult = b.createApply (
1245
+ loc, storageInitRef, storageInitSubs, storageInitArgs);
1246
+
1247
+ // If result was indirect it would already be loaded into
1248
+ // \c storageObj by the call itself.
1249
+ if (!convention.hasIndirectSILResults ())
1250
+ b.createTrivialStoreOr (loc, storageInitResult, storageObj,
1251
+ StoreOwnershipQualifier::Init);
1252
+ }
1253
+
1254
+ // self.$storage = <TypeWrapper>(memberwise: storageObj))
1255
+ {
1256
+ bool isClass = isa<ClassDecl>(parentType);
1257
+
1258
+ auto typeWrapper = parentType->getTypeWrapper ();
1259
+ auto *typeWrapperInit = typeWrapper->getTypeWrapperInitializer ();
1260
+ SILValue typeWrapperInitRef = createInitRef (typeWrapperInit);
1261
+
1262
+ auto *self = TheMemory.findUninitializedSelfValue ();
1263
+
1264
+ SILValue selfRef;
1265
+ if (isClass) {
1266
+ selfRef = b.emitBeginBorrowOperation (loc, self);
1267
+ } else {
1268
+ selfRef = b.createBeginAccess (loc, self, SILAccessKind::Modify,
1269
+ SILAccessEnforcement::Static,
1270
+ /* noNestedConflict=*/ false ,
1271
+ /* fromBuiltin=*/ false );
1272
+ }
1273
+
1274
+ CanSILFunctionType wrapperInitTy =
1275
+ typeWrapperInitRef->getType ().castTo <SILFunctionType>();
1276
+ SILFunctionConventions convention (wrapperInitTy, F.getModule ());
1277
+
1278
+ // Argument is always passed indirectly because it's the
1279
+ // generic parameter `S`.
1280
+
1281
+ // Reference to self.$storage
1282
+ SILValue storagePropRef;
1283
+ if (isClass) {
1284
+ storagePropRef = b.createRefElementAddr (
1285
+ loc, selfRef, parentType->getTypeWrapperProperty ());
1286
+ } else {
1287
+ assert (isa<StructDecl>(parentType));
1288
+ storagePropRef = b.createStructElementAddr (
1289
+ loc, selfRef, parentType->getTypeWrapperProperty ());
1290
+ }
1291
+
1292
+ auto typeWrapperType =
1293
+ b.createMetatype (loc, F.getLoweredType (MetatypeType::get (
1294
+ storagePropRef->getType ().getASTType ())));
1295
+
1296
+ SmallVector<SILValue, 2 > wrapperInitArgs;
1297
+
1298
+ Optional<SILValue> localWrapperObj;
1299
+
1300
+ if (convention.hasIndirectSILResults ()) {
1301
+ assert (convention.getNumIndirectSILResults () == 1 );
1302
+ localWrapperObj = allocStack (storagePropRef->getType ());
1303
+ wrapperInitArgs.push_back (*localWrapperObj);
1304
+ }
1305
+
1306
+ wrapperInitArgs.push_back (storageObj);
1307
+ wrapperInitArgs.push_back (typeWrapperType);
1308
+
1309
+ // <wrapper-var> = <TypeWrapper>.init(memberwise: tmpStorage)
1310
+ auto wrapperInitResult = b.createApply (
1311
+ loc, typeWrapperInitRef,
1312
+ SubstitutionMap::get (typeWrapperInit->getGenericSignature (),
1313
+ /* substitutions=*/ {storageType.getASTType ()},
1314
+ /* conformances=*/ {}),
1315
+ wrapperInitArgs);
1316
+
1317
+ // self.$storage is a property access so it has to has to be wrapped
1318
+ // in begin/end access instructions.
1319
+ {
1320
+ auto storagePropAccess =
1321
+ b.createBeginAccess (loc, storagePropRef, SILAccessKind::Modify,
1322
+ SILAccessEnforcement::Dynamic,
1323
+ /* noNestedConflict=*/ false ,
1324
+ /* fromBuiltin=*/ false );
1325
+
1326
+ // self.$storage = <wrapper-var>
1327
+ {
1328
+ // If the result of `init` is indirect, let's just
1329
+ // initialize the property with it.
1330
+ if (localWrapperObj) {
1331
+ b.createCopyAddr (loc, *localWrapperObj, storagePropAccess, IsTake,
1332
+ IsInitialization);
1333
+ } else {
1334
+ b.createAssign (loc, wrapperInitResult, storagePropAccess,
1335
+ AssignOwnershipQualifier::Init);
1336
+ }
1337
+ }
1338
+
1339
+ b.createEndAccess (loc, storagePropAccess, /* abort=*/ false );
1340
+ }
1341
+
1342
+ if (isClass) {
1343
+ b.emitEndBorrowOperation (loc, selfRef);
1344
+ } else {
1345
+ b.createEndAccess (loc, selfRef, /* aborted=*/ false );
1346
+ }
1347
+
1348
+ // Dealloc all stack allocated data.
1349
+ for (auto alloca = allocations.rbegin (); alloca != allocations.rend ();
1350
+ ++alloca) {
1351
+ b.createDeallocStack (loc, *alloca);
1352
+ }
1353
+ }
1354
+ });
1355
+ }
1356
+ }
1357
+
1073
1358
void LifetimeChecker::doIt () {
1074
1359
// With any escapes tallied up, we can work through all the uses, checking
1075
1360
// for definitive initialization, promoting loads, rewriting assigns, and
@@ -1160,6 +1445,10 @@ void LifetimeChecker::doIt() {
1160
1445
// Insert hop_to_executor instructions for actor initializers, if needed.
1161
1446
injectActorHops ();
1162
1447
1448
+ // Insert `self.$storage` initialization for user-defined initializers
1449
+ // declared in a type wrapped type.
1450
+ injectTypeWrapperStorageInitalization ();
1451
+
1163
1452
// If the memory object had any non-trivial stores that are init or assign
1164
1453
// based on the control flow path reaching them, then insert dynamic control
1165
1454
// logic and CFG diamonds to handle this.
0 commit comments