Skip to content

Commit 896a0b0

Browse files
authored
Merge pull request #25154 from eeckstein/dynamic-replaceable
IRGen/runtime: change the code generation for dynamically replaceable functions
2 parents 7a6f493 + 4fb4435 commit 896a0b0

File tree

11 files changed

+193
-74
lines changed

11 files changed

+193
-74
lines changed

include/swift/Runtime/Exclusivity.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ SWIFT_RUNTIME_EXPORT
4040
void swift_beginAccess(void *pointer, ValueBuffer *buffer,
4141
ExclusivityFlags flags, void *pc);
4242

43+
/// Loads the replacement function pointer from \p ReplFnPtr and returns the
44+
/// replacement function if it should be called.
45+
/// Returns null if the original function (which is passed in \p CurrFn) should
46+
/// be called.
47+
SWIFT_RUNTIME_EXPORT
48+
char *swift_getFunctionReplacement(char **ReplFnPtr, char *CurrFn);
49+
50+
/// Returns the original function of a replaced function, which is loaded from
51+
/// \p OrigFnPtr.
52+
/// This function is called from a replacement function to call the original
53+
/// function.
54+
SWIFT_RUNTIME_EXPORT
55+
char *swift_getOrigOfReplaceable(char **OrigFnPtr);
56+
4357
/// Stop dynamically tracking an access.
4458
SWIFT_RUNTIME_EXPORT
4559
void swift_endAccess(ValueBuffer *buffer);

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,16 @@ FUNCTION(EndAccess, swift_endAccess, C_CC, AlwaysAvailable,
12251225
ARGS(getFixedBufferTy()->getPointerTo()),
12261226
ATTRS(NoUnwind))
12271227

1228+
FUNCTION(GetOrigOfReplaceable, swift_getOrigOfReplaceable, C_CC, AlwaysAvailable,
1229+
RETURNS(FunctionPtrTy),
1230+
ARGS(FunctionPtrTy->getPointerTo()),
1231+
ATTRS(NoUnwind))
1232+
1233+
FUNCTION(GetReplacement, swift_getFunctionReplacement, C_CC, AlwaysAvailable,
1234+
RETURNS(FunctionPtrTy),
1235+
ARGS(FunctionPtrTy->getPointerTo(), FunctionPtrTy),
1236+
ATTRS(NoUnwind))
1237+
12281238
FUNCTION(InstantiateObjCClass, swift_instantiateObjCClass,
12291239
C_CC, AlwaysAvailable,
12301240
RETURNS(VoidTy),

lib/IRGen/GenDecl.cpp

Lines changed: 89 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@
7575
using namespace swift;
7676
using namespace irgen;
7777

78+
llvm::cl::opt<bool> UseBasicDynamicReplacement(
79+
"basic-dynamic-replacement", llvm::cl::init(false),
80+
llvm::cl::desc("Basic implementation of dynamic replacement"));
81+
7882
namespace {
7983

8084
/// Add methods, properties, and protocol conformances from a JITed extension
@@ -2175,6 +2179,79 @@ static llvm::GlobalVariable *createGlobalForDynamicReplacementFunctionKey(
21752179
return key;
21762180
}
21772181

2182+
/// Creates the prolog for a dynamically replaceable function.
2183+
/// It checks if the replaced function or the original function should be called
2184+
/// (by calling the swift_getFunctionReplacement runtime function). In case of
2185+
/// the original function, it just jumps to the "real" code of the function,
2186+
/// otherwise it tail calls the replacement.
2187+
void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) {
2188+
LinkEntity varEntity =
2189+
LinkEntity::forDynamicallyReplaceableFunctionVariable(f);
2190+
LinkEntity keyEntity =
2191+
LinkEntity::forDynamicallyReplaceableFunctionKey(f);
2192+
Signature signature = getSignature(f->getLoweredFunctionType());
2193+
2194+
// Create and initialize the first link entry for the chain of replacements.
2195+
// The first implementation is initialized with 'implFn'.
2196+
auto linkEntry = getChainEntryForDynamicReplacement(*this, varEntity, IGF.CurFn);
2197+
2198+
// Create the key data structure. This is used from other modules to refer to
2199+
// the chain of replacements.
2200+
createGlobalForDynamicReplacementFunctionKey(*this, keyEntity, linkEntry);
2201+
2202+
llvm::Constant *indices[] = {llvm::ConstantInt::get(Int32Ty, 0),
2203+
llvm::ConstantInt::get(Int32Ty, 0)};
2204+
2205+
auto *fnPtrAddr =
2206+
llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices);
2207+
2208+
auto *ReplAddr =
2209+
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(fnPtrAddr,
2210+
FunctionPtrTy->getPointerTo());
2211+
2212+
auto *FnAddr = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
2213+
IGF.CurFn, FunctionPtrTy);
2214+
2215+
llvm::Value *ReplFn = nullptr, *rhs = nullptr;
2216+
2217+
if (UseBasicDynamicReplacement) {
2218+
ReplFn = IGF.Builder.CreateLoad(fnPtrAddr, getPointerAlignment());
2219+
rhs = FnAddr;
2220+
} else {
2221+
// Call swift_getFunctionReplacement to check which function to call.
2222+
auto *callRTFunc = IGF.Builder.CreateCall(getGetReplacementFn(),
2223+
{ ReplAddr, FnAddr });
2224+
callRTFunc->setDoesNotThrow();
2225+
ReplFn = callRTFunc;
2226+
rhs = llvm::ConstantExpr::getNullValue(ReplFn->getType());
2227+
}
2228+
auto *hasReplFn = IGF.Builder.CreateICmpEQ(ReplFn, rhs);
2229+
2230+
auto *replacedBB = IGF.createBasicBlock("forward_to_replaced");
2231+
auto *origEntryBB = IGF.createBasicBlock("original_entry");
2232+
IGF.Builder.CreateCondBr(hasReplFn, origEntryBB, replacedBB);
2233+
2234+
IGF.Builder.emitBlock(replacedBB);
2235+
2236+
// Call the replacement function.
2237+
SmallVector<llvm::Value *, 16> forwardedArgs;
2238+
for (auto &arg : IGF.CurFn->args())
2239+
forwardedArgs.push_back(&arg);
2240+
auto *fnType = signature.getType()->getPointerTo();
2241+
auto *realReplFn = IGF.Builder.CreateBitCast(ReplFn, fnType);
2242+
2243+
auto *Res = IGF.Builder.CreateCall(FunctionPointer(realReplFn, signature),
2244+
forwardedArgs);
2245+
Res->setTailCall();
2246+
if (IGF.CurFn->getReturnType()->isVoidTy())
2247+
IGF.Builder.CreateRetVoid();
2248+
else
2249+
IGF.Builder.CreateRet(Res);
2250+
2251+
IGF.Builder.emitBlock(origEntryBB);
2252+
2253+
}
2254+
21782255
/// Emit the thunk that dispatches to the dynamically replaceable function.
21792256
static void emitDynamicallyReplaceableThunk(IRGenModule &IGM,
21802257
LinkEntity varEntity,
@@ -2279,6 +2356,9 @@ void IRGenModule::emitOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) {
22792356
void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) {
22802357
assert(f->getDynamicallyReplacedFunction());
22812358

2359+
if (UseBasicDynamicReplacement)
2360+
return;
2361+
22822362
auto entity = LinkEntity::forSILFunction(f, true);
22832363

22842364
Signature signature = getSignature(f->getLoweredFunctionType());
@@ -2303,11 +2383,17 @@ void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) {
23032383
llvm::Constant *indices[] = {llvm::ConstantInt::get(Int32Ty, 0),
23042384
llvm::ConstantInt::get(Int32Ty, 0)};
23052385

2306-
auto *fnPtr = IGF.Builder.CreateLoad(
2386+
auto *fnPtrAddr =
2387+
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
23072388
llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices),
2308-
getPointerAlignment());
2389+
FunctionPtrTy->getPointerTo());
2390+
2391+
auto *OrigFn = IGF.Builder.CreateCall(getGetOrigOfReplaceableFn(),
2392+
{ fnPtrAddr });
2393+
OrigFn->setDoesNotThrow();
2394+
23092395
auto *typeFnPtr =
2310-
IGF.Builder.CreateBitOrPointerCast(fnPtr, implFn->getType());
2396+
IGF.Builder.CreateBitOrPointerCast(OrigFn, implFn->getType());
23112397

23122398
SmallVector<llvm::Value *, 16> forwardedArgs;
23132399
for (auto &arg : implFn->args())
@@ -2338,25 +2424,6 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
23382424
if (fn) {
23392425
if (forDefinition) {
23402426
updateLinkageForDefinition(*this, fn, entity);
2341-
if (isDynamicallyReplaceableImplementation) {
2342-
// Create the dynamically replacement thunk.
2343-
LinkEntity implEntity = LinkEntity::forSILFunction(f, true);
2344-
auto existingImpl = Module.getFunction(implEntity.mangleAsString());
2345-
assert(!existingImpl);
2346-
(void) existingImpl;
2347-
Signature signature = getSignature(f->getLoweredFunctionType());
2348-
addLLVMFunctionAttributes(f, signature);
2349-
LinkInfo implLink = LinkInfo::get(*this, implEntity, forDefinition);
2350-
auto implFn = createFunction(*this, implLink, signature, fn,
2351-
f->getOptimizationMode());
2352-
LinkEntity varEntity =
2353-
LinkEntity::forDynamicallyReplaceableFunctionVariable(f);
2354-
LinkEntity keyEntity =
2355-
LinkEntity::forDynamicallyReplaceableFunctionKey(f);
2356-
emitDynamicallyReplaceableThunk(*this, varEntity, keyEntity, fn, implFn,
2357-
signature);
2358-
return implFn;
2359-
}
23602427
}
23612428
return fn;
23622429
}
@@ -2431,20 +2498,6 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
24312498
if (hasOrderNumber) {
24322499
EmittedFunctionsByOrder.insert(orderNumber, fn);
24332500
}
2434-
2435-
if (isDynamicallyReplaceableImplementation && forDefinition) {
2436-
LinkEntity implEntity = LinkEntity::forSILFunction(f, true);
2437-
LinkInfo implLink = LinkInfo::get(*this, implEntity, forDefinition);
2438-
auto implFn = createFunction(*this, implLink, signature, insertBefore,
2439-
f->getOptimizationMode());
2440-
2441-
LinkEntity varEntity =
2442-
LinkEntity::forDynamicallyReplaceableFunctionVariable(f);
2443-
LinkEntity keyEntity = LinkEntity::forDynamicallyReplaceableFunctionKey(f);
2444-
emitDynamicallyReplaceableThunk(*this, varEntity, keyEntity, fn, implFn,
2445-
signature);
2446-
return implFn;
2447-
}
24482501
return fn;
24492502
}
24502503

lib/IRGen/GenDecl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,6 @@ namespace irgen {
5656
}
5757
}
5858

59+
extern llvm::cl::opt<bool> UseBasicDynamicReplacement;
60+
5961
#endif

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,8 @@ private: \
14371437
llvm::Function *getAddrOfOpaqueTypeDescriptorAccessFunction(
14381438
OpaqueTypeDecl *decl, ForDefinition_t forDefinition, bool implementation);
14391439

1440+
void createReplaceableProlog(IRGenFunction &IGF, SILFunction *f);
1441+
14401442
void emitOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *);
14411443

14421444
private:

lib/IRGen/IRGenSIL.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include "GenCast.h"
6161
#include "GenClass.h"
6262
#include "GenConstant.h"
63+
#include "GenDecl.h"
6364
#include "GenEnum.h"
6465
#include "GenExistential.h"
6566
#include "GenFunc.h"
@@ -1244,6 +1245,10 @@ IRGenSILFunction::IRGenSILFunction(IRGenModule &IGM, SILFunction *f)
12441245
if (f->getDynamicallyReplacedFunction()) {
12451246
IGM.emitDynamicReplacementOriginalFunctionThunk(f);
12461247
}
1248+
1249+
if (f->isDynamicallyReplaceable()) {
1250+
IGM.createReplaceableProlog(*this, f);
1251+
}
12471252
}
12481253

12491254
IRGenSILFunction::~IRGenSILFunction() {
@@ -1646,7 +1651,7 @@ void IRGenSILFunction::emitSILFunction() {
16461651
IGM.DebugInfo->emitFunction(*CurSILFn, CurFn);
16471652

16481653
// Map the entry bb.
1649-
LoweredBBs[&*CurSILFn->begin()] = LoweredBB(&*CurFn->begin(), {});
1654+
LoweredBBs[&*CurSILFn->begin()] = LoweredBB(&CurFn->back(), {});
16501655
// Create LLVM basic blocks for the other bbs.
16511656
for (auto bi = std::next(CurSILFn->begin()), be = CurSILFn->end(); bi != be;
16521657
++bi) {
@@ -1870,6 +1875,11 @@ void IRGenSILFunction::visitDynamicFunctionRefInst(DynamicFunctionRefInst *i) {
18701875

18711876
void IRGenSILFunction::visitPreviousDynamicFunctionRefInst(
18721877
PreviousDynamicFunctionRefInst *i) {
1878+
if (UseBasicDynamicReplacement) {
1879+
IGM.unimplemented(i->getLoc().getSourceLoc(),
1880+
": calling the original implementation of a dynamic function is not "
1881+
"supported with -Xllvm -basic-dynamic-replacement");
1882+
}
18731883
visitFunctionRefBaseInst(i);
18741884
}
18751885

lib/TBDGen/TBDGen.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
196196
bool useAllocator = shouldUseAllocatorMangling(AFD);
197197
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(
198198
AFD, useAllocator));
199-
addSymbol(
200-
LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator));
201199
addSymbol(
202200
LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator));
203201

0 commit comments

Comments
 (0)