Skip to content

Commit a5ba65b

Browse files
authored
Merge pull request #3021 from jckarter/behavior-di
2 parents efc351f + 3a8520b commit a5ba65b

File tree

13 files changed

+304
-58
lines changed

13 files changed

+304
-58
lines changed

include/swift/AST/Decl.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,6 +3670,10 @@ enum class AccessStrategy : unsigned char {
36703670
/// The decl is a VarDecl with its own backing storage; evaluate its
36713671
/// address directly.
36723672
Storage,
3673+
3674+
/// The decl is a VarDecl with storage defined by a property behavior;
3675+
/// this access may initialize or reassign the storage based on dataflow.
3676+
BehaviorStorage,
36733677

36743678
/// The decl has addressors; call the appropriate addressor for the
36753679
/// access kind. These calls are currently always direct.
@@ -3700,6 +3704,12 @@ struct BehaviorRecord {
37003704
VarDecl *StorageDecl = nullptr;
37013705
ConcreteDeclRef InitStorageDecl = nullptr;
37023706

3707+
bool needsInitialization() const {
3708+
assert((bool)StorageDecl == (bool)InitStorageDecl
3709+
&& "DI state not consistent");
3710+
return StorageDecl != nullptr;
3711+
}
3712+
37033713
BehaviorRecord(TypeRepr *ProtocolName,
37043714
Expr *Param)
37053715
: ProtocolName(ProtocolName), Param(Param)
@@ -4146,6 +4156,15 @@ class AbstractStorageDecl : public ValueDecl {
41464156
return BehaviorInfo.getPointer() != nullptr;
41474157
}
41484158

4159+
/// Does the storage use a behavior, and require definite initialization
4160+
/// analysis.
4161+
bool hasBehaviorNeedingInitialization() const {
4162+
if (auto behavior = getBehavior()) {
4163+
return behavior->needsInitialization();
4164+
}
4165+
return false;
4166+
}
4167+
41494168
/// Get the behavior info.
41504169
const BehaviorRecord *getBehavior() const {
41514170
return BehaviorInfo.getPointer();

include/swift/AST/Expr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ enum class AccessSemantics : unsigned char {
102102
/// On a property or subscript reference, this is a direct,
103103
/// non-polymorphic access to the getter/setter accessors.
104104
DirectToAccessor,
105+
106+
/// On a property or subscript reference, this is a access to a property
107+
/// behavior that may be an initialization. Reads always go through the
108+
/// 'get' accessor on the property. Writes may go through the 'init' or
109+
/// 'set' logic of the behavior based on its initialization state.
110+
BehaviorInitialization,
105111

106112
/// This is an ordinary access to a declaration, using whatever
107113
/// polymorphism is expected.

include/swift/AST/Mangle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ class Mangler {
135135
/// \param isInitFunc If true it's a globalinit_func, otherwise a
136136
/// globalinit_token.
137137
void mangleGlobalInit(const VarDecl *decl, int counter, bool isInitFunc);
138+
139+
void mangleBehaviorInitThunk(const VarDecl *decl);
138140

139141
void mangleIdentifier(StringRef ref,
140142
OperatorFixity fixity = OperatorFixity::NotOperator,

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,7 @@ static raw_ostream &operator<<(raw_ostream &os, AccessSemantics accessKind) {
14731473
case AccessSemantics::Ordinary: return os;
14741474
case AccessSemantics::DirectToStorage: return os << " direct_to_storage";
14751475
case AccessSemantics::DirectToAccessor: return os << " direct_to_accessor";
1476+
case AccessSemantics::BehaviorInitialization: return os << " behavior_init";
14761477
}
14771478
llvm_unreachable("bad access kind");
14781479
}

lib/AST/Decl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,17 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
12111211
return AccessStrategy::DirectToAccessor;
12121212
}
12131213
llvm_unreachable("bad storage kind");
1214+
case AccessSemantics::BehaviorInitialization:
1215+
// Behavior initialization writes to the property as if it has storage.
1216+
// SIL definite initialization will introduce the logical accesses.
1217+
// Reads or inouts still go through the getter.
1218+
switch (accessKind) {
1219+
case AccessKind::Write:
1220+
return AccessStrategy::BehaviorStorage;
1221+
case AccessKind::ReadWrite:
1222+
case AccessKind::Read:
1223+
return AccessStrategy::DispatchToAccessor;
1224+
}
12141225
}
12151226
llvm_unreachable("bad access semantics");
12161227
}

lib/AST/Mangle.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,3 +1720,19 @@ void Mangler::mangleGlobalInit(const VarDecl *decl, int counter,
17201720
Buffer << (isInitFunc ? "_func" : "_token");
17211721
Buffer << counter;
17221722
}
1723+
1724+
void Mangler::mangleBehaviorInitThunk(const VarDecl *decl) {
1725+
auto topLevelContext = decl->getDeclContext()->getModuleScopeContext();
1726+
auto fileUnit = cast<FileUnit>(topLevelContext);
1727+
Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl);
1728+
assert(!discriminator.empty());
1729+
assert(!isNonAscii(discriminator.str()) &&
1730+
"discriminator contains non-ASCII characters");
1731+
assert(!clang::isDigit(discriminator.str().front()) &&
1732+
"not a valid identifier");
1733+
1734+
Buffer << "_TTB";
1735+
mangleIdentifier(discriminator);
1736+
mangleContextOf(decl);
1737+
mangleIdentifier(decl->getName());
1738+
}

lib/SIL/SILVerifier.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,16 +1051,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
10511051
auto InitStorageTy = InitStorage->getType().getAs<SILFunctionType>();
10521052
require(InitStorageTy,
10531053
"mark_uninitialized initializer must be a function");
1054-
if (auto sig = InitStorageTy->getGenericSignature()) {
1055-
require(sig->getGenericParams().size()
1056-
== MU->getInitStorageSubstitutions().size(),
1057-
"mark_uninitialized initializer must be given right number "
1058-
"of substitutions");
1059-
} else {
1060-
require(MU->getInitStorageSubstitutions().size() == 0,
1061-
"mark_uninitialized initializer must be given right number "
1062-
"of substitutions");
1063-
}
10641054
auto SubstInitStorageTy = InitStorageTy->substGenericArgs(F.getModule(),
10651055
F.getModule().getSwiftModule(),
10661056
MU->getInitStorageSubstitutions());
@@ -1076,16 +1066,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
10761066
auto SetterTy = Setter->getType().getAs<SILFunctionType>();
10771067
require(SetterTy,
10781068
"mark_uninitialized setter must be a function");
1079-
if (auto sig = SetterTy->getGenericSignature()) {
1080-
require(sig->getGenericParams().size()
1081-
== MU->getSetterSubstitutions().size(),
1082-
"mark_uninitialized initializer must be given right number "
1083-
"of substitutions");
1084-
} else {
1085-
require(MU->getSetterSubstitutions().size() == 0,
1086-
"mark_uninitialized initializer must be given right number "
1087-
"of substitutions");
1088-
}
10891069
auto SubstSetterTy = SetterTy->substGenericArgs(F.getModule(),
10901070
F.getModule().getSwiftModule(),
10911071
MU->getSetterSubstitutions());

lib/SILGen/SILGenConstructor.cpp

Lines changed: 138 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
#include "RValue.h"
1818
#include "Scope.h"
1919
#include "swift/AST/AST.h"
20+
#include "swift/AST/Mangle.h"
2021
#include "swift/SIL/SILArgument.h"
22+
#include "swift/SIL/SILUndef.h"
2123
#include "swift/SIL/TypeLowering.h"
2224
#include "swift/Basic/Defer.h"
2325

2426
using namespace swift;
2527
using namespace Lowering;
28+
using namespace Mangle;
2629

2730
static SILValue emitConstructorMetatypeArg(SILGenFunction &gen,
2831
ValueDecl *ctor) {
@@ -692,6 +695,32 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
692695
}
693696
}
694697

698+
static ManagedValue emitSelfForMemberInit(SILGenFunction &SGF, SILLocation loc,
699+
VarDecl *selfDecl) {
700+
CanType selfFormalType = selfDecl->getType()
701+
->getInOutObjectType()->getCanonicalType();
702+
if (selfFormalType->hasReferenceSemantics())
703+
return SGF.emitRValueForDecl(loc, selfDecl, selfDecl->getType(),
704+
AccessSemantics::DirectToStorage,
705+
SGFContext::AllowImmediatePlusZero)
706+
.getAsSingleValue(SGF, loc);
707+
else
708+
return SGF.emitLValueForDecl(loc, selfDecl,
709+
selfDecl->getType()->getCanonicalType(),
710+
AccessKind::Write,
711+
AccessSemantics::DirectToStorage);
712+
}
713+
714+
static LValue emitLValueForMemberInit(SILGenFunction &SGF, SILLocation loc,
715+
VarDecl *selfDecl,
716+
VarDecl *property) {
717+
CanType selfFormalType = selfDecl->getType()
718+
->getInOutObjectType()->getCanonicalType();
719+
auto self = emitSelfForMemberInit(SGF, loc, selfDecl);
720+
return SGF.emitPropertyLValue(loc, self, selfFormalType, property,
721+
AccessKind::Write,
722+
AccessSemantics::DirectToStorage);
723+
}
695724

696725
/// Emit a member initialization for the members described in the
697726
/// given pattern from the given source value.
@@ -720,28 +749,11 @@ static void emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl,
720749
auto named = cast<NamedPattern>(pattern);
721750
// Form the lvalue referencing this member.
722751
WritebackScope scope(SGF);
723-
SILLocation loc = pattern;
724-
ManagedValue self;
725-
CanType selfFormalType = selfDecl->getType()
726-
->getInOutObjectType()->getCanonicalType();
727-
if (selfFormalType->hasReferenceSemantics())
728-
self = SGF.emitRValueForDecl(loc, selfDecl, selfDecl->getType(),
729-
AccessSemantics::DirectToStorage,
730-
SGFContext::AllowImmediatePlusZero)
731-
.getAsSingleValue(SGF, loc);
732-
else
733-
self = SGF.emitLValueForDecl(loc, selfDecl,
734-
src.getType()->getCanonicalType(),
735-
AccessKind::Write,
736-
AccessSemantics::DirectToStorage);
737-
738-
LValue memberRef =
739-
SGF.emitPropertyLValue(loc, self, selfFormalType, named->getDecl(),
740-
AccessKind::Write,
741-
AccessSemantics::DirectToStorage);
752+
LValue memberRef = emitLValueForMemberInit(SGF, pattern, selfDecl,
753+
named->getDecl());
742754

743755
// Assign to it.
744-
SGF.emitAssignToLValue(loc, std::move(src), std::move(memberRef));
756+
SGF.emitAssignToLValue(pattern, std::move(src), std::move(memberRef));
745757
return;
746758
}
747759

@@ -765,20 +777,117 @@ static void emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl,
765777
}
766778
}
767779

780+
static SILValue getBehaviorInitStorageFn(SILGenFunction &gen,
781+
VarDecl *behaviorVar) {
782+
std::string behaviorInitName;
783+
{
784+
Mangler m;
785+
m.mangleBehaviorInitThunk(behaviorVar);
786+
behaviorInitName = m.finalize();
787+
}
788+
789+
SILFunction *thunkFn;
790+
// Skip out early if we already emitted this thunk.
791+
if (auto existing = gen.SGM.M.lookUpFunction(behaviorInitName)) {
792+
thunkFn = existing;
793+
} else {
794+
auto init = behaviorVar->getBehavior()->InitStorageDecl.getDecl();
795+
auto initFn = gen.SGM.getFunction(SILDeclRef(init), NotForDefinition);
796+
797+
// Emit a thunk to inject the `self` metatype and implode tuples.
798+
auto storageVar = behaviorVar->getBehavior()->StorageDecl;
799+
auto selfTy = behaviorVar->getDeclContext()->getDeclaredInterfaceType();
800+
auto initTy = gen.getLoweredType(selfTy).getFieldType(behaviorVar,
801+
gen.SGM.M);
802+
auto storageTy = gen.getLoweredType(selfTy).getFieldType(storageVar,
803+
gen.SGM.M);
804+
805+
auto initConstantTy = initFn->getLoweredType().castTo<SILFunctionType>();
806+
807+
auto param = SILParameterInfo(initTy.getSwiftRValueType(),
808+
initTy.isAddress() ? ParameterConvention::Indirect_In
809+
: ParameterConvention::Direct_Owned);
810+
auto result = SILResultInfo(storageTy.getSwiftRValueType(),
811+
storageTy.isAddress() ? ResultConvention::Indirect
812+
: ResultConvention::Owned);
813+
814+
initConstantTy = SILFunctionType::get(initConstantTy->getGenericSignature(),
815+
initConstantTy->getExtInfo(),
816+
ParameterConvention::Direct_Unowned,
817+
param,
818+
result,
819+
// TODO: throwing initializer?
820+
None,
821+
gen.getASTContext());
822+
823+
// TODO: Generate the body of the thunk.
824+
thunkFn = gen.SGM.M.getOrCreateFunction(SILLocation(behaviorVar),
825+
behaviorInitName,
826+
SILLinkage::PrivateExternal,
827+
initConstantTy,
828+
IsBare, IsTransparent, IsFragile);
829+
830+
831+
}
832+
return gen.B.createFunctionRef(behaviorVar, thunkFn);
833+
}
834+
835+
static SILValue getBehaviorSetterFn(SILGenFunction &gen, VarDecl *behaviorVar) {
836+
auto set = behaviorVar->getSetter();
837+
auto setFn = gen.SGM.getFunction(SILDeclRef(set), NotForDefinition);
838+
839+
// TODO: The setter may need to be a thunk, to implode tuples or perform
840+
// reabstractions.
841+
return gen.B.createFunctionRef(behaviorVar, setFn);
842+
}
843+
768844
void SILGenFunction::emitMemberInitializers(VarDecl *selfDecl,
769845
NominalTypeDecl *nominal) {
770846
for (auto member : nominal->getMembers()) {
771-
// Find pattern binding declarations that have initializers.
772-
auto pbd = dyn_cast<PatternBindingDecl>(member);
773-
if (!pbd || pbd->isStatic()) continue;
847+
// Find instance pattern binding declarations that have initializers.
848+
if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
849+
if (pbd->isStatic()) continue;
774850

775-
for (auto entry : pbd->getPatternList()) {
776-
auto init = entry.getInit();
777-
if (!init) continue;
851+
for (auto entry : pbd->getPatternList()) {
852+
auto init = entry.getInit();
853+
if (!init) continue;
778854

779-
// Cleanup after this initialization.
780-
FullExpr scope(Cleanups, entry.getPattern());
781-
emitMemberInit(*this, selfDecl, entry.getPattern(), emitRValue(init));
855+
// Cleanup after this initialization.
856+
FullExpr scope(Cleanups, entry.getPattern());
857+
emitMemberInit(*this, selfDecl, entry.getPattern(), emitRValue(init));
858+
}
859+
}
860+
861+
// Introduce behavior initialization markers for properties that need them.
862+
if (auto var = dyn_cast<VarDecl>(member)) {
863+
if (var->isStatic()) continue;
864+
if (!var->hasBehaviorNeedingInitialization()) continue;
865+
866+
// Get the initializer method for behavior.
867+
auto init = var->getBehavior()->InitStorageDecl;
868+
SILValue initFn = getBehaviorInitStorageFn(*this, var);
869+
870+
// Get the behavior's storage we need to initialize.
871+
auto storage = var->getBehavior()->StorageDecl;
872+
LValue storageRef = emitLValueForMemberInit(*this, var, selfDecl,storage);
873+
// Shed any reabstraction over the member.
874+
while (storageRef.isLastComponentTranslation())
875+
storageRef.dropLastTranslationComponent();
876+
877+
auto storageAddr = emitAddressOfLValue(var, std::move(storageRef),
878+
AccessKind::ReadWrite);
879+
880+
// Get the setter.
881+
auto setterFn = getBehaviorSetterFn(*this, var);
882+
auto self = emitSelfForMemberInit(*this, var, selfDecl);
883+
884+
auto mark = B.createMarkUninitializedBehavior(var,
885+
initFn, init.getSubstitutions(), storageAddr.getValue(),
886+
setterFn, getForwardingSubstitutions(), self.getValue(),
887+
getLoweredType(var->getType()).getAddressType());
888+
889+
// The mark instruction stands in for the behavior property.
890+
VarLocs[var].value = mark;
782891
}
783892
}
784893
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ ManagedValue SILGenFunction::emitLValueForDecl(SILLocation loc, VarDecl *var,
284284
case AccessStrategy::DirectToAccessor:
285285
case AccessStrategy::DispatchToAccessor:
286286
return ManagedValue();
287+
288+
case AccessStrategy::BehaviorStorage:
289+
// TODO: Behaviors aren't supported on non-instance properties yet.
290+
llvm_unreachable("not implemented");
287291
}
288292
llvm_unreachable("bad access strategy");
289293
}
@@ -462,6 +466,9 @@ static SILDeclRef getRValueAccessorDeclRef(SILGenFunction &SGF,
462466
AbstractStorageDecl *storage,
463467
AccessStrategy strategy) {
464468
switch (strategy) {
469+
case AccessStrategy::BehaviorStorage:
470+
llvm_unreachable("shouldn't load an rvalue via behavior storage!");
471+
465472
case AccessStrategy::Storage:
466473
llvm_unreachable("should already have been filtered out!");
467474

@@ -491,6 +498,9 @@ emitRValueWithAccessor(SILGenFunction &SGF, SILLocation loc,
491498
bool isDirectUse = (strategy == AccessStrategy::DirectToAccessor);
492499

493500
switch (strategy) {
501+
case AccessStrategy::BehaviorStorage:
502+
llvm_unreachable("shouldn't load an rvalue via behavior storage!");
503+
494504
case AccessStrategy::Storage:
495505
llvm_unreachable("should already have been filtered out!");
496506

0 commit comments

Comments
 (0)