Skip to content

Commit 6c0e391

Browse files
committed
[SILGen] InitAccessor: Emit init accessor function
Emit all initializes/accesses properties as arguments in custom prolog and map them back to the originating property declarations.
1 parent 5bac6e8 commit 6c0e391

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

lib/SILGen/SILGen.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,16 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
875875
break;
876876
}
877877

878+
if (constant.isInitAccessor()) {
879+
auto *accessor = cast<AccessorDecl>(constant.getDecl());
880+
preEmitFunction(constant, f, accessor);
881+
PrettyStackTraceSILFunction X("silgen init accessor", f);
882+
f->createProfiler(constant);
883+
SILGenFunction(*this, *f, accessor).emitInitAccessor(accessor);
884+
postEmitFunction(constant, f);
885+
break;
886+
}
887+
878888
auto *fd = cast<FuncDecl>(constant.getDecl());
879889

880890
preEmitFunction(constant, f, fd);

lib/SILGen/SILGenConstructor.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,3 +1481,81 @@ void SILGenFunction::emitIVarInitializer(SILDeclRef ivarInitializer) {
14811481

14821482
emitEpilog(loc);
14831483
}
1484+
1485+
void SILGenFunction::emitInitAccessor(AccessorDecl *accessor) {
1486+
RegularLocation loc(accessor);
1487+
loc.markAutoGenerated();
1488+
1489+
auto accessorTy = F.getLoweredFunctionType();
1490+
1491+
auto createArgument = [&](VarDecl *property, SILType type,
1492+
bool markUninitialized = false) {
1493+
auto *arg = ParamDecl::createImplicit(
1494+
getASTContext(), property->getBaseIdentifier(),
1495+
property->getBaseIdentifier(), type.getASTType()->mapTypeOutOfContext(),
1496+
accessor, ParamSpecifier::InOut);
1497+
1498+
RegularLocation loc(property);
1499+
loc.markAutoGenerated();
1500+
1501+
SILValue argValue = F.begin()->createFunctionArgument(type, arg);
1502+
VarLocs[arg] =
1503+
markUninitialized
1504+
? VarLoc::get(B.createMarkUninitializedOut(loc, argValue))
1505+
: VarLoc::get(argValue);
1506+
1507+
InitAccessorArgumentMappings[property] = arg;
1508+
};
1509+
1510+
// First, emit results, this is our "initializes(...)" properties and
1511+
// require DI to check that each property is fully initialized.
1512+
if (auto *initAttr = accessor->getAttrs().getAttribute<InitializesAttr>()) {
1513+
auto initializedProperties = initAttr->getPropertyDecls(accessor);
1514+
for (unsigned i = 0, n = initializedProperties.size(); i != n; ++i) {
1515+
auto *property = initializedProperties[i];
1516+
auto propertyTy =
1517+
getSILTypeInContext(accessorTy->getResults()[i], accessorTy);
1518+
createArgument(property, propertyTy, /*markUninitialized=*/true);
1519+
}
1520+
}
1521+
1522+
// Collect all of the parameters that represent properties listed by
1523+
// "accesses" attribute. They have to be emitted in order of arguments which
1524+
// means after the "newValue" which is emitted by \c emitBasicProlog.
1525+
Optional<ArrayRef<VarDecl *>> accessedProperties;
1526+
{
1527+
if (auto *accessAttr = accessor->getAttrs().getAttribute<AccessesAttr>())
1528+
accessedProperties = accessAttr->getPropertyDecls(accessor);
1529+
}
1530+
1531+
// Emit `newValue` argument.
1532+
emitBasicProlog(accessor->getParameters(), /*selfParam=*/nullptr,
1533+
TupleType::getEmpty(F.getASTContext()), accessor,
1534+
/*throws=*/false, /*throwsLoc=*/SourceLoc(),
1535+
/*ignored parameters*/
1536+
accessedProperties ? accessedProperties->size() : 0);
1537+
1538+
// Emit arguments for all `accesses(...)` properties.
1539+
if (accessedProperties) {
1540+
auto propertyIter = accessedProperties->begin();
1541+
auto propertyArgs = accessorTy->getParameters().slice(
1542+
accessorTy->getNumParameters() - accessedProperties->size());
1543+
1544+
for (const auto &argument : propertyArgs) {
1545+
createArgument(*propertyIter, getSILTypeInContext(argument, accessorTy));
1546+
++propertyIter;
1547+
}
1548+
}
1549+
1550+
prepareEpilog(accessor->getResultInterfaceType(), accessor->hasThrows(),
1551+
CleanupLocation(accessor));
1552+
1553+
emitProfilerIncrement(accessor->getTypecheckedBody());
1554+
1555+
// Emit the actual function body as usual
1556+
emitStmt(accessor->getTypecheckedBody());
1557+
1558+
emitEpilog(accessor);
1559+
1560+
mergeCleanupBlocks();
1561+
}

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
804804
/// Emit a method that destroys the ivars of a class.
805805
void emitIVarDestroyer(SILDeclRef ivarDestroyer);
806806

807+
/// Generates code for the given init accessor represented by AccessorDecl.
808+
/// This emits the body code and replaces all `self.<property>` references
809+
/// with either argument (if property appears in `acesses` list`) or result
810+
/// value assignment.
811+
void emitInitAccessor(AccessorDecl *accessor);
812+
807813
/// Generates code to destroy the instance variables of a class.
808814
///
809815
/// \param selfValue The 'self' value.

0 commit comments

Comments
 (0)