Skip to content

Commit d765434

Browse files
committed
[IRGen] Restored non-constant async function calls in PAFs.
Previously, because partial apply forwarders for async functions were not themselves fully-fledged async functions, they were not able to handle dynamic functions. Specifically, the reason was that it was not possible to produce an async function pointer for the partial apply forwarder because the size to be used was not knowable. Thanks to swiftlang#36700, that cause has been eliminated. With it, partial apply forwarders are fully-fledged async functions and in particular have their own async function pointers. Consequently, it is again possible for these partial apply forwarders to handle non-constant function pointers. Here, that behavior is restored, by way of reverting part of ee63777 while preserving the ABI it introduced. rdar://76122027
1 parent 19d9ebd commit d765434

15 files changed

+79
-714
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ struct PointerAuthOptions : clang::PointerAuthOptions {
159159
/// values.
160160
PointerAuthSchema AsyncSwiftDynamicReplacements;
161161

162+
/// Like PartialApplyCapture but for use with AsyncFunctionPointer values.
163+
PointerAuthSchema AsyncPartialApplyCapture;
164+
162165
/// The parent async context stored within a child async context.
163166
PointerAuthSchema AsyncContextParent;
164167

include/swift/IRGen/IRGenSILPasses.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ namespace irgen {
1919
/// Create a pass to hoist alloc_stack instructions with non-fixed size.
2020
SILTransform *createAllocStackHoisting();
2121
SILTransform *createLoadableByAddress();
22-
SILTransform *createPartialApplyLowering();
2322

2423
} // end namespace irgen
2524
} // end namespace swift

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,6 @@ IRGEN_PASS(LoadableByAddress, "loadable-address",
298298
"SIL Large Loadable type by-address lowering.")
299299
PASS(MandatorySILLinker, "mandatory-linker",
300300
"Deserialize all referenced SIL functions that are shared or transparent")
301-
IRGEN_PASS(PartialApplyLowering, "partial-apply-lowering",
302-
"Partial Apply Lowering")
303301
PASS(PerformanceSILLinker, "performance-linker",
304302
"Deserialize all referenced SIL functions")
305303
PASS(RawSILInstLowering, "raw-sil-inst-lowering",

lib/IRGen/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ add_swift_host_library(swiftIRGen STATIC
5252
MetadataLayout.cpp
5353
MetadataRequest.cpp
5454
Outlining.cpp
55-
PartialApplyLowering.cpp
5655
StructLayout.cpp
5756
SwiftTargetInfo.cpp
5857
TypeLayout.cpp

lib/IRGen/Explosion.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ class Explosion {
9797
Values.append(values.begin(), values.end());
9898
}
9999

100+
void insert(unsigned index, llvm::Value *value) {
101+
Values.insert(Values.begin() + index, value);
102+
}
103+
100104
/// Return an array containing the given range of values. The values
101105
/// are not claimed.
102106
ArrayRef<llvm::Value*> getRange(unsigned from, unsigned to) const {

lib/IRGen/GenFunc.cpp

Lines changed: 48 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -768,15 +768,12 @@ class PartialApplicationForwarderEmission {
768768
origParams(subIGF.collectParameters()) {}
769769

770770
public:
771-
enum class DynamicFunctionKind {
772-
Witness,
773-
PartialApply,
774-
};
775771
virtual void begin(){};
776772

777773
virtual void gatherArgumentsFromApply() = 0;
778774

779-
virtual void mapAsyncParameters() {}
775+
virtual void mapAsyncParameters(FunctionPointer fnPtr) {}
776+
virtual void recordAsyncParametersInsertionPoint(){};
780777

781778
void gatherArgumentsFromApply(bool isAsync) {
782779
// Lower the forwarded arguments in the original function's generic context.
@@ -831,7 +828,7 @@ class PartialApplicationForwarderEmission {
831828
}
832829

833830
if (isAsync)
834-
mapAsyncParameters();
831+
recordAsyncParametersInsertionPoint();
835832

836833
// Reemit the parameters as unsubstituted.
837834
for (unsigned i = 0; i < outType->getParameters().size(); ++i) {
@@ -921,12 +918,10 @@ class PartialApplicationForwarderEmission {
921918

922919
llvm::Value *getContext() { return origParams.claimNext(); }
923920

924-
virtual llvm::Value *getDynamicFunctionPointer(PointerAuthInfo &authInfo) = 0;
921+
virtual llvm::Value *getDynamicFunctionPointer() = 0;
925922
virtual llvm::Value *getDynamicFunctionContext() = 0;
926-
virtual void addDynamicFunctionContext(Explosion &explosion,
927-
DynamicFunctionKind kind) = 0;
928-
virtual void addDynamicFunctionPointer(Explosion &explosion,
929-
DynamicFunctionKind kind) = 0;
923+
virtual void addDynamicFunctionContext(Explosion &explosion) = 0;
924+
virtual void addDynamicFunctionPointer(Explosion &explosion) = 0;
930925

931926
void addSelf(Explosion &explosion) { addArgument(explosion); }
932927
void addWitnessSelfMetadata(llvm::Value *value) {
@@ -965,16 +960,12 @@ class SyncPartialApplicationForwarderEmission
965960
void gatherArgumentsFromApply() override {
966961
super::gatherArgumentsFromApply(false);
967962
}
968-
llvm::Value *getDynamicFunctionPointer(PointerAuthInfo &authInfo) override {
969-
return args.takeLast();
970-
}
963+
llvm::Value *getDynamicFunctionPointer() override { return args.takeLast(); }
971964
llvm::Value *getDynamicFunctionContext() override { return args.takeLast(); }
972-
void addDynamicFunctionContext(Explosion &explosion,
973-
DynamicFunctionKind kind) override {
965+
void addDynamicFunctionContext(Explosion &explosion) override {
974966
addArgument(explosion);
975967
}
976-
void addDynamicFunctionPointer(Explosion &explosion,
977-
DynamicFunctionKind kind) override {
968+
void addDynamicFunctionPointer(Explosion &explosion) override {
978969
addArgument(explosion);
979970
}
980971
void forwardErrorResult() override {
@@ -1045,13 +1036,6 @@ class AsyncPartialApplicationForwarderEmission
10451036
Address context;
10461037
Address calleeContextBuffer;
10471038
unsigned currentArgumentIndex;
1048-
struct DynamicFunction {
1049-
using Kind = DynamicFunctionKind;
1050-
Kind kind;
1051-
llvm::Value *pointer;
1052-
llvm::Value *context;
1053-
};
1054-
Optional<DynamicFunction> dynamicFunction = llvm::None;
10551039
struct Self {
10561040
enum class Kind {
10571041
Method,
@@ -1061,6 +1045,7 @@ class AsyncPartialApplicationForwarderEmission
10611045
llvm::Value *value;
10621046
};
10631047
Optional<Self> self = llvm::None;
1048+
unsigned asyncParametersInsertionIndex = 0;
10641049

10651050
void saveValue(ElementLayout layout, Explosion &explosion) {
10661051
Address addr = layout.project(subIGF, context, /*offsets*/ llvm::None);
@@ -1088,24 +1073,28 @@ class AsyncPartialApplicationForwarderEmission
10881073

10891074
void begin() override { super::begin(); }
10901075

1091-
void mapAsyncParameters() override {
1076+
void recordAsyncParametersInsertionPoint() override {
10921077
// Ignore the original context.
10931078
(void)origParams.claimNext();
10941079

1080+
asyncParametersInsertionIndex = args.size();
1081+
}
1082+
void mapAsyncParameters(FunctionPointer fnPtr) override {
10951083
llvm::Value *dynamicContextSize32;
10961084
auto initialContextSize = Size(0);
10971085
std::tie(calleeFunction, dynamicContextSize32) = getAsyncFunctionAndSize(
1098-
subIGF, origType->getRepresentation(), *staticFnPtr,
1099-
nullptr, std::make_pair(true, true), initialContextSize);
1086+
subIGF, origType->getRepresentation(), fnPtr, nullptr,
1087+
std::make_pair(true, true), initialContextSize);
11001088
auto *dynamicContextSize =
11011089
subIGF.Builder.CreateZExt(dynamicContextSize32, subIGF.IGM.SizeTy);
11021090
calleeContextBuffer =
11031091
emitAllocAsyncContext(subIGF, dynamicContextSize);
11041092
context = layout.emitCastTo(subIGF, calleeContextBuffer.getAddress());
11051093
auto calleeContext =
11061094
layout.emitCastTo(subIGF, calleeContextBuffer.getAddress());
1107-
args.add(subIGF.Builder.CreateBitOrPointerCast(
1108-
calleeContextBuffer.getAddress(), IGM.SwiftContextPtrTy));
1095+
args.insert(asyncParametersInsertionIndex,
1096+
subIGF.Builder.CreateBitOrPointerCast(
1097+
calleeContextBuffer.getAddress(), IGM.SwiftContextPtrTy));
11091098

11101099
// Set caller info into the context.
11111100
{ // caller context
@@ -1146,20 +1135,14 @@ class AsyncPartialApplicationForwarderEmission
11461135
void gatherArgumentsFromApply() override {
11471136
super::gatherArgumentsFromApply(true);
11481137
}
1149-
llvm::Value *getDynamicFunctionPointer(PointerAuthInfo &authInfo) override {
1150-
llvm_unreachable(
1151-
"async partial applies never have dynamic function pointers");
1152-
}
1138+
llvm::Value *getDynamicFunctionPointer() override { return args.takeLast(); }
11531139
llvm::Value *getDynamicFunctionContext() override {
11541140
return args.takeLast();
11551141
}
1156-
void addDynamicFunctionContext(Explosion &explosion,
1157-
DynamicFunction::Kind kind) override {
1142+
void addDynamicFunctionContext(Explosion &explosion) override {
11581143
addArgument(explosion);
11591144
}
1160-
void addDynamicFunctionPointer(Explosion &explosion,
1161-
DynamicFunction::Kind kind) override {
1162-
assert(false);
1145+
void addDynamicFunctionPointer(Explosion &explosion) override {
11631146
addArgument(explosion);
11641147
}
11651148

@@ -1669,20 +1652,10 @@ static llvm::Value *emitPartialApplicationForwarder(IRGenModule &IGM,
16691652
} else {
16701653
switch (extraFieldIndex) {
16711654
case 0:
1672-
emission->addDynamicFunctionContext(
1673-
param, isWitnessMethodCallee
1674-
? PartialApplicationForwarderEmission::
1675-
DynamicFunctionKind::Witness
1676-
: PartialApplicationForwarderEmission::
1677-
DynamicFunctionKind::PartialApply);
1655+
emission->addDynamicFunctionContext(param);
16781656
break;
16791657
case 1:
1680-
emission->addDynamicFunctionPointer(
1681-
param, isWitnessMethodCallee
1682-
? PartialApplicationForwarderEmission::
1683-
DynamicFunctionKind::Witness
1684-
: PartialApplicationForwarderEmission::
1685-
DynamicFunctionKind::PartialApply);
1658+
emission->addDynamicFunctionPointer(param);
16861659
break;
16871660
default:
16881661
llvm_unreachable("unexpected extra field in thick context");
@@ -1724,22 +1697,29 @@ static llvm::Value *emitPartialApplicationForwarder(IRGenModule &IGM,
17241697
// Otherwise, it was the last thing we added to the layout.
17251698

17261699
assert(lastCapturedFieldPtr);
1727-
auto authInfo = PointerAuthInfo::emit(subIGF,
1728-
IGM.getOptions().PointerAuth.PartialApplyCapture,
1729-
lastCapturedFieldPtr,
1730-
PointerAuthEntity::Special::PartialApplyCapture);
1700+
auto authInfo = PointerAuthInfo::emit(
1701+
subIGF,
1702+
origType->isAsync()
1703+
? IGM.getOptions().PointerAuth.AsyncPartialApplyCapture
1704+
: IGM.getOptions().PointerAuth.PartialApplyCapture,
1705+
lastCapturedFieldPtr, PointerAuthEntity::Special::PartialApplyCapture);
17311706

17321707
// The dynamic function pointer is packed "last" into the context,
17331708
// and we pulled it out as an argument. Just pop it off.
1734-
auto fnPtr = emission->getDynamicFunctionPointer(authInfo);
1709+
auto fnPtr = emission->getDynamicFunctionPointer();
17351710

17361711
// It comes out of the context as an i8*. Cast to the function type.
17371712
fnPtr = subIGF.Builder.CreateBitCast(fnPtr, fnTy);
17381713

1739-
return FunctionPointer(FunctionPointer::Kind::Function, fnPtr, authInfo,
1740-
origSig);
1714+
return FunctionPointer(origType->isAsync()
1715+
? FunctionPointer::Kind::AsyncFunctionPointer
1716+
: FunctionPointer::Kind::Function,
1717+
fnPtr, authInfo, origSig);
17411718
}();
17421719

1720+
if (origType->isAsync())
1721+
emission->mapAsyncParameters(fnPtr);
1722+
17431723
// Derive the context argument if needed. This is either:
17441724
// - the saved context argument, in which case it was the last
17451725
// thing we added to the layout other than a possible non-static
@@ -1770,12 +1750,7 @@ static llvm::Value *emitPartialApplicationForwarder(IRGenModule &IGM,
17701750
if (isMethodCallee) {
17711751
emission->addSelf(explosion);
17721752
} else {
1773-
emission->addDynamicFunctionContext(
1774-
explosion, isWitnessMethodCallee
1775-
? PartialApplicationForwarderEmission::
1776-
DynamicFunctionKind::Witness
1777-
: PartialApplicationForwarderEmission::
1778-
DynamicFunctionKind::PartialApply);
1753+
emission->addDynamicFunctionContext(explosion);
17791754
}
17801755

17811756
// Pass a placeholder for thin function calls.
@@ -2120,16 +2095,18 @@ Optional<StackAddress> irgen::emitFunctionPartialApplication(
21202095
// We don't add non-constant function pointers to the explosion above,
21212096
// so we need to handle them specially now.
21222097
if (i == nonStaticFnIndex) {
2123-
llvm::Value *fnPtr;
2124-
if (auto &schema = IGF.getOptions().PointerAuth.PartialApplyCapture) {
2125-
auto schemaAuthInfo =
2126-
PointerAuthInfo::emit(IGF, schema, fieldAddr.getAddress(),
2127-
PointerAuthEntity::Special::PartialApplyCapture);
2098+
llvm::Value *fnPtr = fn.getRawPointer();
2099+
if (auto &schema =
2100+
origType->isAsync()
2101+
? IGF.getOptions().PointerAuth.AsyncPartialApplyCapture
2102+
: IGF.getOptions().PointerAuth.PartialApplyCapture) {
2103+
auto schemaAuthInfo = PointerAuthInfo::emit(
2104+
IGF, schema, fieldAddr.getAddress(),
2105+
PointerAuthEntity::Special::PartialApplyCapture);
21282106
fnPtr =
21292107
emitPointerAuthResign(IGF, fn, schemaAuthInfo).getRawPointer();
2130-
} else {
2131-
fnPtr = fn.getRawPointer();
21322108
}
2109+
21332110
fnPtr = IGF.Builder.CreateBitCast(fnPtr, IGF.IGM.Int8PtrTy);
21342111
IGF.Builder.CreateStore(fnPtr, fieldAddr);
21352112
continue;

lib/IRGen/IRGen.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,11 @@ static void setPointerAuthOptions(PointerAuthOptions &opts,
644644
// might end up on a global constant initializer.
645645
auto nonABICodeKey = PointerAuthSchema::ARM8_3Key::ASIB;
646646

647+
// A key suitable for data pointers that are only used in private
648+
// situations. Do not use this key for any sort of signature that
649+
// might end up on a global constant initializer.
650+
auto nonABIDataKey = PointerAuthSchema::ARM8_3Key::ASDB;
651+
647652
// If you change anything here, be sure to update <ptrauth.h>.
648653
opts.SwiftFunctionPointers =
649654
PointerAuthSchema(codeKey, /*address*/ false, Discrimination::Type);
@@ -712,6 +717,9 @@ static void setPointerAuthOptions(PointerAuthOptions &opts,
712717
opts.AsyncSwiftDynamicReplacements =
713718
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Decl);
714719

720+
opts.AsyncPartialApplyCapture =
721+
PointerAuthSchema(nonABIDataKey, /*address*/ true, Discrimination::Decl);
722+
715723
opts.AsyncContextParent =
716724
PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Constant,
717725
SpecialPointerAuthDiscriminators::AsyncContextParent);

0 commit comments

Comments
 (0)