mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
IRGen: Add implementation for dynamically replaceable functions
A dynamically replaceable function calls through a global variable that
holds the function pointer.
struct ChainEntry {
void *(funPtr)();
struct ChainEntry *next;
}
ChainEntry dynamicallyReplaceableVar;
void dynamicallyReplaceableFunction() {
dynamicallyReplaceableVar.funPtr()
}
dynamic replacements will be chainable so the global variable also
functions as the root entry in the chain of replacements.
A dynamic replacement functions can call the previous implementation by
going through its chain entry.
ChainEntry chainEntryOf_dynamic_replacement_for_foo;
void dynamic_replacement_for_foo() {
// call the previous (original) implementation.
chainEntryOf_dynamic_replacement_for_foo.funPtr();
}
This commit is contained in:
@@ -171,7 +171,7 @@ types where the metadata itself has unknown layout.)
|
||||
global ::= global 'To' // swift-as-ObjC thunk
|
||||
global ::= global 'TD' // dynamic dispatch thunk
|
||||
global ::= global 'Td' // direct method reference thunk
|
||||
global ::= global 'TR' // implementation of a dynamic_replaceable function
|
||||
global ::= global 'TI' // implementation of a dynamic_replaceable function
|
||||
global ::= global 'TX' // function pointer of a dynamic_replaceable function
|
||||
global ::= entity entity 'TV' // vtable override thunk, derived followed by base
|
||||
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.
|
||||
|
||||
@@ -71,6 +71,8 @@ NODE(Directness)
|
||||
NODE(DynamicAttribute)
|
||||
NODE(DirectMethodReferenceAttribute)
|
||||
NODE(DynamicSelf)
|
||||
NODE(DynamicallyReplaceableFunctionImpl)
|
||||
NODE(DynamicallyReplaceableFunctionVar)
|
||||
CONTEXT_NODE(Enum)
|
||||
NODE(EnumCase)
|
||||
NODE(ErrorType)
|
||||
|
||||
@@ -103,6 +103,10 @@ class LinkEntity {
|
||||
// This field appears in associated conformance access functions.
|
||||
AssociatedConformanceIndexShift = 8,
|
||||
AssociatedConformanceIndexMask = ~KindMask,
|
||||
|
||||
// This field appears in SILFunction.
|
||||
IsDynamicallyReplaceableImplShift = 8,
|
||||
IsDynamicallyReplaceableImplMask = ~KindMask,
|
||||
};
|
||||
#define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
|
||||
#define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
|
||||
@@ -226,6 +230,14 @@ class LinkEntity {
|
||||
/// is stored in the data.
|
||||
DefaultAssociatedConformanceAccessor,
|
||||
|
||||
/// The original implementation of a dynamically replaceable function.
|
||||
/// The pointer is a AbstractStorageDecl*.
|
||||
DynamicallyReplaceableFunctionImpl,
|
||||
|
||||
/// A global function pointer for dynamically replaceable functions.
|
||||
/// The pointer is a AbstractStorageDecl*.
|
||||
DynamicallyReplaceableFunctionVariableAST,
|
||||
|
||||
/// A SIL function. The pointer is a SILFunction*.
|
||||
SILFunction,
|
||||
|
||||
@@ -315,6 +327,9 @@ class LinkEntity {
|
||||
|
||||
/// A coroutine continuation prototype function.
|
||||
CoroutineContinuationPrototype,
|
||||
|
||||
/// A global function pointer for dynamically replaceable functions.
|
||||
DynamicallyReplaceableFunctionVariable,
|
||||
};
|
||||
friend struct llvm::DenseMapInfo<LinkEntity>;
|
||||
|
||||
@@ -323,7 +338,7 @@ class LinkEntity {
|
||||
}
|
||||
|
||||
static bool isDeclKind(Kind k) {
|
||||
return k <= Kind::DefaultAssociatedConformanceAccessor;
|
||||
return k <= Kind::DynamicallyReplaceableFunctionVariableAST;
|
||||
}
|
||||
static bool isTypeKind(Kind k) {
|
||||
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
|
||||
@@ -705,12 +720,15 @@ public:
|
||||
return entity;
|
||||
}
|
||||
|
||||
static LinkEntity forSILFunction(SILFunction *F)
|
||||
{
|
||||
static LinkEntity
|
||||
forSILFunction(SILFunction *F, bool IsDynamicallyReplaceableImplementation) {
|
||||
LinkEntity entity;
|
||||
entity.Pointer = F;
|
||||
entity.SecondaryPointer = nullptr;
|
||||
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILFunction));
|
||||
entity.Data =
|
||||
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILFunction)) |
|
||||
LINKENTITY_SET_FIELD(IsDynamicallyReplaceableImpl,
|
||||
(unsigned)IsDynamicallyReplaceableImplementation);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -837,6 +855,29 @@ public:
|
||||
return entity;
|
||||
}
|
||||
|
||||
static LinkEntity forDynamicallyReplaceableFunctionVariable(SILFunction *F) {
|
||||
LinkEntity entity;
|
||||
entity.Pointer = F;
|
||||
entity.SecondaryPointer = nullptr;
|
||||
entity.Data = LINKENTITY_SET_FIELD(
|
||||
Kind, unsigned(Kind::DynamicallyReplaceableFunctionVariable));
|
||||
return entity;
|
||||
}
|
||||
|
||||
static LinkEntity
|
||||
forDynamicallyReplaceableFunctionVariable(AbstractFunctionDecl *decl) {
|
||||
LinkEntity entity;
|
||||
entity.setForDecl(Kind::DynamicallyReplaceableFunctionVariableAST, decl);
|
||||
return entity;
|
||||
}
|
||||
|
||||
static LinkEntity
|
||||
forDynamicallyReplaceableFunctionImpl(AbstractFunctionDecl *decl) {
|
||||
LinkEntity entity;
|
||||
entity.setForDecl(Kind::DynamicallyReplaceableFunctionImpl, decl);
|
||||
return entity;
|
||||
}
|
||||
|
||||
void mangle(llvm::raw_ostream &out) const;
|
||||
void mangle(SmallVectorImpl<char> &buffer) const;
|
||||
std::string mangleAsString() const;
|
||||
@@ -863,7 +904,8 @@ public:
|
||||
}
|
||||
|
||||
SILFunction *getSILFunction() const {
|
||||
assert(getKind() == Kind::SILFunction);
|
||||
assert(getKind() == Kind::SILFunction ||
|
||||
getKind() == Kind::DynamicallyReplaceableFunctionVariable);
|
||||
return reinterpret_cast<SILFunction*>(Pointer);
|
||||
}
|
||||
|
||||
@@ -899,7 +941,10 @@ public:
|
||||
assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
|
||||
return reinterpret_cast<ProtocolDecl*>(Pointer);
|
||||
}
|
||||
|
||||
bool isDynamicallyReplaceable() const {
|
||||
assert(getKind() == Kind::SILFunction);
|
||||
return LINKENTITY_GET_FIELD(Data, IsDynamicallyReplaceableImpl);
|
||||
}
|
||||
bool isValueWitness() const { return getKind() == Kind::ValueWitness; }
|
||||
CanType getType() const {
|
||||
assert(isTypeKind(getKind()));
|
||||
|
||||
@@ -111,6 +111,8 @@ static bool isFunctionAttr(Node::Kind kind) {
|
||||
case Node::Kind::OutlinedVariable:
|
||||
case Node::Kind::OutlinedBridgedMethod:
|
||||
case Node::Kind::MergedFunction:
|
||||
case Node::Kind::DynamicallyReplaceableFunctionImpl:
|
||||
case Node::Kind::DynamicallyReplaceableFunctionVar:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -1933,6 +1935,8 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
|
||||
case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
|
||||
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
|
||||
case 'm': return createNode(Node::Kind::MergedFunction);
|
||||
case 'X': return createNode(Node::Kind::DynamicallyReplaceableFunctionVar);
|
||||
case 'I': return createNode(Node::Kind::DynamicallyReplaceableFunctionImpl);
|
||||
case 'C': {
|
||||
NodePointer type = popNode(Node::Kind::Type);
|
||||
return createWithChild(Node::Kind::CoroutineContinuationPrototype, type);
|
||||
|
||||
@@ -493,6 +493,8 @@ private:
|
||||
case Node::Kind::DependentProtocolConformanceInherited:
|
||||
case Node::Kind::DependentProtocolConformanceRoot:
|
||||
case Node::Kind::ProtocolConformanceRef:
|
||||
case Node::Kind::DynamicallyReplaceableFunctionImpl:
|
||||
case Node::Kind::DynamicallyReplaceableFunctionVar:
|
||||
return false;
|
||||
}
|
||||
printer_unreachable("bad node kind");
|
||||
@@ -1521,6 +1523,16 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
|
||||
Printer << "type symbolic reference 0x";
|
||||
Printer.writeHex(Node->getIndex());
|
||||
return nullptr;
|
||||
case Node::Kind::DynamicallyReplaceableFunctionImpl:
|
||||
if (!Options.ShortenThunk) {
|
||||
Printer << "dynamically replaceable thunk for ";
|
||||
}
|
||||
return nullptr;
|
||||
case Node::Kind::DynamicallyReplaceableFunctionVar:
|
||||
if (!Options.ShortenThunk) {
|
||||
Printer << "dynamically replaceable variable for ";
|
||||
}
|
||||
return nullptr;
|
||||
case Node::Kind::ProtocolSymbolicReference:
|
||||
Printer << "protocol symbolic reference 0x";
|
||||
Printer.writeHex(Node->getIndex());
|
||||
|
||||
@@ -832,6 +832,14 @@ void Remangler::mangleMergedFunction(Node *node) {
|
||||
Out << "Tm";
|
||||
}
|
||||
|
||||
void Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node) {
|
||||
Out << "TI";
|
||||
}
|
||||
|
||||
void Remangler::mangleDynamicallyReplaceableFunctionVar(Node *node) {
|
||||
Out << "TX";
|
||||
}
|
||||
|
||||
void Remangler::mangleDirectness(Node *node) {
|
||||
auto getChar = [](Directness d) -> char {
|
||||
switch (d) {
|
||||
|
||||
@@ -1255,6 +1255,8 @@ void Remangler::mangleGlobal(Node *node) {
|
||||
case Node::Kind::VTableAttribute:
|
||||
case Node::Kind::DirectMethodReferenceAttribute:
|
||||
case Node::Kind::MergedFunction:
|
||||
case Node::Kind::DynamicallyReplaceableFunctionImpl:
|
||||
case Node::Kind::DynamicallyReplaceableFunctionVar:
|
||||
mangleInReverseOrder = true;
|
||||
break;
|
||||
default:
|
||||
@@ -1587,6 +1589,14 @@ void Remangler::mangleMergedFunction(Node *node) {
|
||||
Buffer << "Tm";
|
||||
}
|
||||
|
||||
void Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node) {
|
||||
Buffer << "TI";
|
||||
}
|
||||
|
||||
void Remangler::mangleDynamicallyReplaceableFunctionVar(Node *node) {
|
||||
Buffer << "TX";
|
||||
}
|
||||
|
||||
void Remangler::manglePostfixOperator(Node *node) {
|
||||
mangleIdentifierImpl(node, /*isOperator*/ true);
|
||||
Buffer << "oP";
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
|
||||
#include "Callee.h"
|
||||
#include "ConstantBuilder.h"
|
||||
#include "Explosion.h"
|
||||
#include "FixedTypeInfo.h"
|
||||
@@ -1272,6 +1273,44 @@ void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::GlobalVariable *IRGenModule::getGlobalForDynamicallyReplaceableThunk(
|
||||
LinkEntity &entity, llvm::Type *type, ForDefinition_t forDefinition) {
|
||||
return cast<llvm::GlobalVariable>(
|
||||
getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo()));
|
||||
}
|
||||
|
||||
/// Creates a dynamic replacement chain entry for \p SILFn that contains either
|
||||
/// the implementation function pointer \p or a nullptr, the next pointer of the
|
||||
/// chain entry is set to nullptr.
|
||||
/// struct ChainEntry {
|
||||
/// void *funPtr;
|
||||
/// struct ChainEntry *next;
|
||||
/// }
|
||||
static llvm::GlobalVariable *getChainEntryForDynamicReplacement(
|
||||
IRGenModule &IGM, SILFunction *SILFn,
|
||||
llvm::Function *implFunction = nullptr,
|
||||
ForDefinition_t forDefinition = ForDefinition) {
|
||||
|
||||
LinkEntity entity =
|
||||
LinkEntity::forDynamicallyReplaceableFunctionVariable(SILFn);
|
||||
auto linkEntry = IGM.getGlobalForDynamicallyReplaceableThunk(
|
||||
entity, IGM.DynamicReplacementLinkEntryTy, forDefinition);
|
||||
if (!forDefinition)
|
||||
return linkEntry;
|
||||
|
||||
auto *funPtr =
|
||||
implFunction ? llvm::ConstantExpr::getBitCast(implFunction, IGM.Int8PtrTy)
|
||||
: llvm::ConstantExpr::getNullValue(IGM.Int8PtrTy);
|
||||
auto *nextEntry =
|
||||
llvm::ConstantExpr::getNullValue(IGM.DynamicReplacementLinkEntryPtrTy);
|
||||
llvm::Constant *fields[] = {funPtr, nextEntry};
|
||||
auto *entry =
|
||||
llvm::ConstantStruct::get(IGM.DynamicReplacementLinkEntryTy, fields);
|
||||
linkEntry->setInitializer(entry);
|
||||
return linkEntry;
|
||||
}
|
||||
|
||||
|
||||
void IRGenerator::emitEagerClassInitialization() {
|
||||
if (ClassesForEagerInitialization.empty())
|
||||
return;
|
||||
@@ -1893,16 +1932,95 @@ static clang::GlobalDecl getClangGlobalDeclForFunction(const clang::Decl *decl)
|
||||
return clang::GlobalDecl(cast<clang::FunctionDecl>(decl));
|
||||
}
|
||||
|
||||
static void addLLVMFunctionAttributes(SILFunction *f, Signature &signature) {
|
||||
auto &attrs = signature.getMutableAttributes();
|
||||
switch (f->getInlineStrategy()) {
|
||||
case NoInline:
|
||||
attrs = attrs.addAttribute(signature.getType()->getContext(),
|
||||
llvm::AttributeList::FunctionIndex,
|
||||
llvm::Attribute::NoInline);
|
||||
break;
|
||||
case AlwaysInline:
|
||||
// FIXME: We do not currently transfer AlwaysInline since doing so results
|
||||
// in test failures, which must be investigated first.
|
||||
case InlineDefault:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isReadOnlyFunction(f)) {
|
||||
attrs = attrs.addAttribute(signature.getType()->getContext(),
|
||||
llvm::AttributeList::FunctionIndex,
|
||||
llvm::Attribute::ReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit the thunk that dispatches to the dynamically replaceable function.
|
||||
static void emitDynamicallyReplaceableThunk(IRGenModule &IGM,
|
||||
SILFunction *SILFn,
|
||||
llvm::Function *dispatchFn,
|
||||
llvm::Function *implFn,
|
||||
Signature &signature) {
|
||||
|
||||
// Create and initialize the first link entry for the chain of replacements.
|
||||
// The first implementation is initialized with 'implFn'.
|
||||
auto linkEntry = getChainEntryForDynamicReplacement(IGM, SILFn, implFn);
|
||||
|
||||
// We should never inline the implementation function.
|
||||
implFn->addFnAttr(llvm::Attribute::NoInline);
|
||||
|
||||
// Load the function and dispatch to it forwarding our arguments.
|
||||
llvm::BasicBlock *entryBB =
|
||||
llvm::BasicBlock::Create(IGM.getLLVMContext(), "entry", dispatchFn);
|
||||
IRBuilder B(IGM.getLLVMContext(), false);
|
||||
B.SetInsertPoint(entryBB);
|
||||
llvm::Constant *indices[] = {llvm::ConstantInt::get(IGM.Int32Ty, 0),
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, 0)};
|
||||
auto *fnPtr = B.CreateLoad(
|
||||
llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices),
|
||||
IGM.getPointerAlignment());
|
||||
auto *typeFnPtr = B.CreateBitOrPointerCast(fnPtr, implFn->getType());
|
||||
SmallVector<llvm::Value *, 16> forwardedArgs;
|
||||
for (auto &arg : dispatchFn->args())
|
||||
forwardedArgs.push_back(&arg);
|
||||
auto *Res =
|
||||
B.CreateCall(FunctionPointer(typeFnPtr, signature), forwardedArgs);
|
||||
if (implFn->getReturnType()->isVoidTy())
|
||||
B.CreateRetVoid();
|
||||
else
|
||||
B.CreateRet(Res);
|
||||
|
||||
}
|
||||
|
||||
/// Find the entry point for a SIL function.
|
||||
llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
|
||||
ForDefinition_t forDefinition) {
|
||||
LinkEntity entity = LinkEntity::forSILFunction(f);
|
||||
llvm::Function *
|
||||
IRGenModule::getAddrOfSILFunction(SILFunction *f, ForDefinition_t forDefinition,
|
||||
bool isDynamicallyReplaceableImplementation) {
|
||||
assert(forDefinition || !isDynamicallyReplaceableImplementation);
|
||||
|
||||
LinkEntity entity =
|
||||
LinkEntity::forSILFunction(f, false);
|
||||
|
||||
// Check whether we've created the function already.
|
||||
// FIXME: We should integrate this into the LinkEntity cache more cleanly.
|
||||
llvm::Function *fn = Module.getFunction(f->getName());
|
||||
llvm::Function *fn = Module.getFunction(entity.mangleAsString());
|
||||
if (fn) {
|
||||
if (forDefinition) updateLinkageForDefinition(*this, fn, entity);
|
||||
if (forDefinition) {
|
||||
updateLinkageForDefinition(*this, fn, entity);
|
||||
// Create the dynamically repl
|
||||
LinkEntity implEntity = LinkEntity::forSILFunction(f, true);
|
||||
if (isDynamicallyReplaceableImplementation) {
|
||||
auto existingImpl = Module.getFunction(implEntity.mangleAsString());
|
||||
assert(!existingImpl);
|
||||
(void) existingImpl;
|
||||
Signature signature = getSignature(f->getLoweredFunctionType());
|
||||
addLLVMFunctionAttributes(f, signature);
|
||||
LinkInfo implLink = LinkInfo::get(*this, implEntity, forDefinition);
|
||||
auto implFn = createFunction(*this, implLink, signature, fn,
|
||||
f->getOptimizationMode());
|
||||
emitDynamicallyReplaceableThunk(*this, f, fn, implFn, signature);
|
||||
return implFn;
|
||||
}
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
@@ -1953,28 +2071,10 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
|
||||
}
|
||||
|
||||
Signature signature = getSignature(f->getLoweredFunctionType());
|
||||
auto &attrs = signature.getMutableAttributes();
|
||||
addLLVMFunctionAttributes(f, signature);
|
||||
|
||||
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
|
||||
|
||||
switch (f->getInlineStrategy()) {
|
||||
case NoInline:
|
||||
attrs = attrs.addAttribute(signature.getType()->getContext(),
|
||||
llvm::AttributeList::FunctionIndex,
|
||||
llvm::Attribute::NoInline);
|
||||
break;
|
||||
case AlwaysInline:
|
||||
// FIXME: We do not currently transfer AlwaysInline since doing so results
|
||||
// in test failures, which must be investigated first.
|
||||
case InlineDefault:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isReadOnlyFunction(f)) {
|
||||
attrs = attrs.addAttribute(signature.getType()->getContext(),
|
||||
llvm::AttributeList::FunctionIndex,
|
||||
llvm::Attribute::ReadOnly);
|
||||
}
|
||||
fn = createFunction(*this, link, signature, insertBefore,
|
||||
f->getOptimizationMode());
|
||||
|
||||
@@ -1990,6 +2090,16 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
|
||||
if (hasOrderNumber) {
|
||||
EmittedFunctionsByOrder.insert(orderNumber, fn);
|
||||
}
|
||||
|
||||
if (isDynamicallyReplaceableImplementation && forDefinition) {
|
||||
LinkEntity implEntity = LinkEntity::forSILFunction(f, true);
|
||||
LinkInfo implLink = LinkInfo::get(*this, implEntity, forDefinition);
|
||||
auto implFn = createFunction(*this, implLink, signature, insertBefore,
|
||||
f->getOptimizationMode());
|
||||
|
||||
emitDynamicallyReplaceableThunk(*this, f, fn, implFn, signature);
|
||||
return implFn;
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
||||
@@ -458,6 +458,16 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
|
||||
IsSwiftErrorInRegister =
|
||||
clang::CodeGen::swiftcall::isSwiftErrorLoweredInRegister(
|
||||
ClangCodeGen->CGM());
|
||||
|
||||
DynamicReplacementLinkEntryTy =
|
||||
llvm::StructType::create(getLLVMContext(), "swift.dyn_repl_link_entry");
|
||||
DynamicReplacementLinkEntryPtrTy =
|
||||
DynamicReplacementLinkEntryTy->getPointerTo(DefaultAS);
|
||||
llvm::Type *linkEntryFields[] = {
|
||||
Int8PtrTy, // function pointer.
|
||||
DynamicReplacementLinkEntryPtrTy // next.
|
||||
};
|
||||
DynamicReplacementLinkEntryTy->setBody(linkEntryFields);
|
||||
}
|
||||
|
||||
IRGenModule::~IRGenModule() {
|
||||
|
||||
@@ -641,6 +641,10 @@ public:
|
||||
llvm::Type *FloatTy;
|
||||
llvm::Type *DoubleTy;
|
||||
|
||||
llvm::StructType *DynamicReplacementLinkEntryTy; // %link_entry = { i8*, %link_entry*}
|
||||
llvm::PointerType
|
||||
*DynamicReplacementLinkEntryPtrTy; // %link_entry*
|
||||
|
||||
llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr;
|
||||
|
||||
/// Used to create unique names for class layout types with tail allocated
|
||||
@@ -1317,11 +1321,14 @@ public:
|
||||
Address getAddrOfObjCClassRef(ClassDecl *D);
|
||||
llvm::Constant *getAddrOfMetaclassObject(ClassDecl *D,
|
||||
ForDefinition_t forDefinition);
|
||||
|
||||
llvm::Function *getAddrOfObjCMetadataUpdateFunction(ClassDecl *D,
|
||||
ForDefinition_t forDefinition);
|
||||
|
||||
llvm::Function *getAddrOfSILFunction(SILFunction *f,
|
||||
ForDefinition_t forDefinition);
|
||||
llvm::Function *
|
||||
getAddrOfSILFunction(SILFunction *f, ForDefinition_t forDefinition,
|
||||
bool IsDynamicallyReplaceableImplementation = false);
|
||||
|
||||
llvm::Function *getAddrOfContinuationPrototype(CanSILFunctionType fnType);
|
||||
Address getAddrOfSILGlobalVariable(SILGlobalVariable *var,
|
||||
const TypeInfo &ti,
|
||||
@@ -1384,6 +1391,10 @@ public:
|
||||
|
||||
void ensureRelativeSymbolCollocation(SILWitnessTable &wt);
|
||||
|
||||
llvm::GlobalVariable *
|
||||
getGlobalForDynamicallyReplaceableThunk(LinkEntity &entity, llvm::Type *type,
|
||||
ForDefinition_t forDefinition);
|
||||
|
||||
private:
|
||||
llvm::Constant *
|
||||
getAddrOfSharedContextDescriptor(LinkEntity entity,
|
||||
|
||||
@@ -1207,11 +1207,12 @@ llvm::Value *LoweredValue::getSingletonExplosion(IRGenFunction &IGF,
|
||||
llvm_unreachable("bad kind");
|
||||
}
|
||||
|
||||
IRGenSILFunction::IRGenSILFunction(IRGenModule &IGM,
|
||||
SILFunction *f)
|
||||
: IRGenFunction(IGM, IGM.getAddrOfSILFunction(f, ForDefinition),
|
||||
f->getOptimizationMode(),
|
||||
f->getDebugScope(), f->getLocation()),
|
||||
IRGenSILFunction::IRGenSILFunction(IRGenModule &IGM, SILFunction *f)
|
||||
: IRGenFunction(IGM,
|
||||
IGM.getAddrOfSILFunction(f, ForDefinition,
|
||||
f->isDynamicallyReplaceable()),
|
||||
f->getOptimizationMode(), f->getDebugScope(),
|
||||
f->getLocation()),
|
||||
CurSILFn(f) {
|
||||
// Apply sanitizer attributes to the function.
|
||||
// TODO: Check if the function is supposed to be excluded from ASan either by
|
||||
|
||||
@@ -264,8 +264,45 @@ std::string LinkEntity::mangleAsString() const {
|
||||
return Result;
|
||||
}
|
||||
|
||||
case Kind::SILFunction:
|
||||
return getSILFunction()->getName();
|
||||
case Kind::SILFunction: {
|
||||
std::string Result(getSILFunction()->getName());
|
||||
if (isDynamicallyReplaceable()) {
|
||||
Result.append("TI");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
case Kind::DynamicallyReplaceableFunctionImpl: {
|
||||
assert(isa<AbstractFunctionDecl>(getDecl()));
|
||||
std::string Result;
|
||||
if (auto *Constructor = dyn_cast<ConstructorDecl>(getDecl())) {
|
||||
Result = mangler.mangleConstructorEntity(Constructor, true,
|
||||
/*isCurried=*/false);
|
||||
} else {
|
||||
Result = mangler.mangleEntity(getDecl(), /*isCurried=*/false);
|
||||
}
|
||||
Result.append("TI");
|
||||
return Result;
|
||||
}
|
||||
|
||||
case Kind::DynamicallyReplaceableFunctionVariable: {
|
||||
std::string Result(getSILFunction()->getName());
|
||||
Result.append("TX");
|
||||
return Result;
|
||||
}
|
||||
|
||||
case Kind::DynamicallyReplaceableFunctionVariableAST: {
|
||||
assert(isa<AbstractFunctionDecl>(getDecl()));
|
||||
std::string Result;
|
||||
if (auto *Constructor = dyn_cast<ConstructorDecl>(getDecl())) {
|
||||
Result = mangler.mangleConstructorEntity(Constructor, true,
|
||||
/*isCurried=*/false);
|
||||
} else {
|
||||
Result = mangler.mangleEntity(getDecl(), /*isCurried=*/false);
|
||||
}
|
||||
Result.append("TX");
|
||||
return Result;
|
||||
}
|
||||
|
||||
case Kind::SILGlobalVariable:
|
||||
return getSILGlobalVariable()->getName();
|
||||
|
||||
@@ -494,6 +531,14 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
|
||||
case Kind::SILFunction:
|
||||
return getSILFunction()->getEffectiveSymbolLinkage();
|
||||
|
||||
case Kind::DynamicallyReplaceableFunctionImpl:
|
||||
return getSILLinkage(getDeclLinkage(getDecl()), forDefinition);
|
||||
|
||||
case Kind::DynamicallyReplaceableFunctionVariable:
|
||||
return getSILFunction()->getEffectiveSymbolLinkage();
|
||||
case Kind::DynamicallyReplaceableFunctionVariableAST:
|
||||
return getSILLinkage(getDeclLinkage(getDecl()), forDefinition);
|
||||
|
||||
case Kind::SILGlobalVariable:
|
||||
return getSILGlobalVariable()->getLinkage();
|
||||
|
||||
@@ -623,6 +668,8 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
|
||||
case Kind::TypeMetadataPattern:
|
||||
case Kind::DefaultAssociatedConformanceAccessor:
|
||||
return false;
|
||||
case Kind::DynamicallyReplaceableFunctionVariable:
|
||||
return true;
|
||||
|
||||
case Kind::SILFunction:
|
||||
return ::isAvailableExternally(IGM, getSILFunction());
|
||||
@@ -647,6 +694,8 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
|
||||
case Kind::ReflectionFieldDescriptor:
|
||||
case Kind::ReflectionAssociatedTypeDescriptor:
|
||||
case Kind::CoroutineContinuationPrototype:
|
||||
case Kind::DynamicallyReplaceableFunctionVariableAST:
|
||||
case Kind::DynamicallyReplaceableFunctionImpl:
|
||||
llvm_unreachable("Relative reference to unsupported link entity");
|
||||
}
|
||||
llvm_unreachable("bad link entity kind");
|
||||
@@ -728,6 +777,8 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const {
|
||||
case Kind::MethodDescriptorAllocator:
|
||||
return IGM.MethodDescriptorStructTy;
|
||||
|
||||
case Kind::DynamicallyReplaceableFunctionVariable:
|
||||
return IGM.DynamicReplacementLinkEntryTy;
|
||||
default:
|
||||
llvm_unreachable("declaration LLVM type not specified");
|
||||
}
|
||||
@@ -768,6 +819,7 @@ Alignment LinkEntity::getAlignment(IRGenModule &IGM) const {
|
||||
case Kind::ProtocolWitnessTablePattern:
|
||||
case Kind::ObjCMetaclass:
|
||||
case Kind::SwiftMetaclassStub:
|
||||
case Kind::DynamicallyReplaceableFunctionVariable:
|
||||
return IGM.getPointerAlignment();
|
||||
case Kind::SILFunction:
|
||||
return Alignment(1);
|
||||
@@ -783,6 +835,7 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
|
||||
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
|
||||
return false;
|
||||
|
||||
case Kind::DynamicallyReplaceableFunctionVariable:
|
||||
case Kind::SILFunction: {
|
||||
// For imported functions check the Clang declaration.
|
||||
if (auto clangOwner = getSILFunction()->getClangNodeOwner())
|
||||
@@ -833,6 +886,8 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
|
||||
case Kind::ProtocolDescriptor:
|
||||
case Kind::ProtocolRequirementsBaseDescriptor:
|
||||
case Kind::AssociatedTypeDescriptor:
|
||||
case Kind::DynamicallyReplaceableFunctionVariableAST:
|
||||
case Kind::DynamicallyReplaceableFunctionImpl:
|
||||
return getDecl()->isWeakImported(module);
|
||||
|
||||
// TODO: Revisit some of the below, for weak conformances.
|
||||
@@ -905,12 +960,15 @@ const SourceFile *LinkEntity::getSourceFileForEmission() const {
|
||||
case Kind::AssociatedTypeDescriptor:
|
||||
case Kind::AssociatedConformanceDescriptor:
|
||||
case Kind::DefaultAssociatedConformanceAccessor:
|
||||
case Kind::DynamicallyReplaceableFunctionVariableAST:
|
||||
case Kind::DynamicallyReplaceableFunctionImpl:
|
||||
sf = getSourceFileForDeclContext(getDecl()->getDeclContext());
|
||||
if (!sf)
|
||||
return nullptr;
|
||||
break;
|
||||
|
||||
case Kind::SILFunction:
|
||||
case Kind::DynamicallyReplaceableFunctionVariable:
|
||||
sf = getSourceFileForDeclContext(getSILFunction()->getDeclContext());
|
||||
if (!sf)
|
||||
return nullptr;
|
||||
|
||||
@@ -164,6 +164,12 @@ void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
|
||||
|
||||
addSymbol(SILDeclRef(AFD));
|
||||
|
||||
// Add the global function pointer for a dynamically replaceable function.
|
||||
if (AFD->isDynamic() && ! AFD->isObjC()) {
|
||||
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(AFD));
|
||||
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD));
|
||||
}
|
||||
|
||||
if (AFD->getAttrs().hasAttribute<CDeclAttr>()) {
|
||||
// A @_cdecl("...") function has an extra symbol, with the name from the
|
||||
// attribute.
|
||||
|
||||
25
test/IRGen/dynamic_replaceable.sil
Normal file
25
test/IRGen/dynamic_replaceable.sil
Normal file
@@ -0,0 +1,25 @@
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir -disable-objc-interop | %FileCheck %s
|
||||
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
// CHECK: @test_dynamically_replaceableTX = global %swift.dyn_repl_link_entry { i8* bitcast (void ()* @test_dynamically_replaceableTI to i8*), %swift.dyn_repl_link_entry* null }
|
||||
// CHECK: @llvm.used = appending global {{.*}} @test_dynamically_replaceable {{.*}} @test_dynamically_replaceableTX
|
||||
|
||||
// CHECK-LABEL: define swiftcc void @test_dynamically_replaceable()
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[FUN_PTR:%.*]] = load i8*, i8** getelementptr inbounds (%swift.dyn_repl_link_entry, %swift.dyn_repl_link_entry* @test_dynamically_replaceableTX, i32 0, i32 0)
|
||||
// CHECK-NEXT: [[TYPED_PTR:%.*]] = bitcast i8* [[FUN_PTR]] to void ()*
|
||||
// CHECK-NEXT: call swiftcc void [[TYPED_PTR]]()
|
||||
// CHECK-NEXT: ret void
|
||||
// CHECK-NEXT: }
|
||||
|
||||
// CHECK-LABEL: define swiftcc void @test_dynamically_replaceableTI()
|
||||
// CHECK: entry:
|
||||
// CHECK: ret void
|
||||
// CHECK: }
|
||||
|
||||
sil [dynamically_replacable] @test_dynamically_replaceable : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = tuple ()
|
||||
return %0 : $()
|
||||
}
|
||||
Reference in New Issue
Block a user