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:
Arnold Schwaighofer
2018-08-24 07:07:09 -07:00
parent 5f4e183302
commit ebbe3aed1c
14 changed files with 343 additions and 41 deletions

View File

@@ -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.

View File

@@ -71,6 +71,8 @@ NODE(Directness)
NODE(DynamicAttribute)
NODE(DirectMethodReferenceAttribute)
NODE(DynamicSelf)
NODE(DynamicallyReplaceableFunctionImpl)
NODE(DynamicallyReplaceableFunctionVar)
CONTEXT_NODE(Enum)
NODE(EnumCase)
NODE(ErrorType)

View File

@@ -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()));

View File

@@ -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);

View File

@@ -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());

View File

@@ -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) {

View File

@@ -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";

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View 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 : $()
}