Skip to content

Method descriptors #19067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ field offsets are therefore required when accessing fields in generic
types where the metadata itself has unknown layout.)

::
global ::= global 'Tj' // resilient method dispatch thunk
global ::= global 'Tq' // method descriptor

global ::= global 'TO' // ObjC-as-swift thunk
global ::= global 'To' // swift-as-ObjC thunk
Expand Down
1 change: 0 additions & 1 deletion include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class ASTMangler : public Mangler {
enum class SymbolKind {
Default,
DynamicThunk,
SwiftDispatchThunk,
SwiftAsObjCThunk,
ObjCAsSwiftThunk,
DirectMethodReferenceThunk,
Expand Down
5 changes: 3 additions & 2 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,9 @@ NODE(ReflectionMetadataFieldDescriptor)
NODE(ReflectionMetadataAssocTypeDescriptor)
NODE(ReflectionMetadataSuperclassDescriptor)
NODE(GenericTypeParamDecl)
CONTEXT_NODE(CurryThunk)
CONTEXT_NODE(DispatchThunk)
NODE(CurryThunk)
NODE(DispatchThunk)
NODE(MethodDescriptor)
NODE(ThrowsAnnotation)
NODE(EmptyList)
NODE(FirstElementMarker)
Expand Down
57 changes: 48 additions & 9 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ class LinkEntity {
/// ConstructorDecl* inside a protocol or a class.
DispatchThunkAllocator,

/// A method descriptor. The pointer is a FuncDecl* inside a protocol
/// or a class.
MethodDescriptor,

/// A method descriptor for an initializing constructor. The pointer
/// is a ConstructorDecl* inside a class.
MethodDescriptorInitializer,

/// A method descriptor for an allocating constructor. The pointer is a
/// ConstructorDecl* inside a protocol or a class.
MethodDescriptorAllocator,

/// A resilient enum tag index. The pointer is a EnumElementDecl*.
EnumCase,

Expand Down Expand Up @@ -412,18 +424,22 @@ class LinkEntity {

LinkEntity() = default;

static bool isValidResilientMethodRef(SILDeclRef declRef) {
if (declRef.isForeign ||
declRef.isDirectReference ||
declRef.isCurried)
return false;

auto *decl = declRef.getDecl();
return (isa<ClassDecl>(decl->getDeclContext()) ||
isa<ProtocolDecl>(decl->getDeclContext()));
}

public:
static LinkEntity forDispatchThunk(SILDeclRef declRef) {
assert(!declRef.isForeign &&
!declRef.isDirectReference &&
!declRef.isCurried);
assert(isValidResilientMethodRef(declRef));

LinkEntity::Kind kind;

auto *decl = declRef.getDecl();
assert(isa<ClassDecl>(decl->getDeclContext()) ||
isa<ProtocolDecl>(decl->getDeclContext()));

switch (declRef.kind) {
case SILDeclRef::Kind::Func:
kind = Kind::DispatchThunk;
Expand All @@ -439,7 +455,30 @@ class LinkEntity {
}

LinkEntity entity;
entity.setForDecl(kind, decl);
entity.setForDecl(kind, declRef.getDecl());
return entity;
}

static LinkEntity forMethodDescriptor(SILDeclRef declRef) {
assert(isValidResilientMethodRef(declRef));

LinkEntity::Kind kind;
switch (declRef.kind) {
case SILDeclRef::Kind::Func:
kind = Kind::MethodDescriptor;
break;
case SILDeclRef::Kind::Initializer:
kind = Kind::MethodDescriptorInitializer;
break;
case SILDeclRef::Kind::Allocator:
kind = Kind::MethodDescriptorAllocator;
break;
default:
llvm_unreachable("Bad SILDeclRef for method descriptor");
}

LinkEntity entity;
entity.setForDecl(kind, declRef.getDecl());
return entity;
}

Expand Down
1 change: 0 additions & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,6 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) {
switch (SKind) {
case SymbolKind::Default: return;
case SymbolKind::DynamicThunk: return appendOperator("TD");
case SymbolKind::SwiftDispatchThunk: return appendOperator("Tj");
case SymbolKind::SwiftAsObjCThunk: return appendOperator("To");
case SymbolKind::ObjCAsSwiftThunk: return appendOperator("TO");
case SymbolKind::DirectMethodReferenceThunk: return appendOperator("Td");
Expand Down
1 change: 1 addition & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,7 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
switch (char c = nextChar()) {
case 'c': return createWithChild(Node::Kind::CurryThunk, popNode(isEntity));
case 'j': return createWithChild(Node::Kind::DispatchThunk, popNode(isEntity));
case 'q': return createWithChild(Node::Kind::MethodDescriptor, popNode(isEntity));
case 'o': return createNode(Node::Kind::ObjCAttribute);
case 'O': return createNode(Node::Kind::NonObjCAttribute);
case 'D': return createNode(Node::Kind::DynamicAttribute);
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ class NodePrinter {
case Node::Kind::MaterializeForSet:
case Node::Kind::MergedFunction:
case Node::Kind::Metaclass:
case Node::Kind::MethodDescriptor:
case Node::Kind::ModifyAccessor:
case Node::Kind::NativeOwningAddressor:
case Node::Kind::NativeOwningMutableAddressor:
Expand Down Expand Up @@ -907,6 +908,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
Printer << "dispatch thunk of ";
print(Node->getChild(0));
return nullptr;
case Node::Kind::MethodDescriptor:
Printer << "method descriptor for ";
print(Node->getChild(0));
return nullptr;
case Node::Kind::OutlinedBridgedMethod:
Printer << "outlined bridged method (" << Node->getText() << ") of ";
return nullptr;
Expand Down
8 changes: 6 additions & 2 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1931,14 +1931,18 @@ void Remangler::mangleGenericTypeParamDecl(Node *node) {
unreachable("todo");
}

void Remangler::mangleCurryThunk(Node *node, EntityContext &ctx) {
void Remangler::mangleCurryThunk(Node *node) {
Out << "<curry-thunk>";
}

void Remangler::mangleDispatchThunk(Node *node, EntityContext &ctx) {
void Remangler::mangleDispatchThunk(Node *node) {
Out << "<dispatch-thunk>";
}

void Remangler::mangleMethodDescriptor(Node *node) {
Out << "<method-descriptor>";
}

void Remangler::mangleEmptyList(Node *node) {
Out << "<empty>";
}
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,11 @@ void Remangler::mangleDispatchThunk(Node *node) {
Buffer << "Tj";
}

void Remangler::mangleMethodDescriptor(Node *node) {
mangleSingleChildNode(node);
Buffer << "Tq";
}

void Remangler::mangleThrowsAnnotation(Node *node) {
Buffer << 'K';
}
Expand Down
30 changes: 0 additions & 30 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,36 +1019,6 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {

emitNestedTypeDecls(D->getMembers());
emitFieldMetadataRecord(D);

// If the class is resilient, emit dispatch thunks.
if (isResilient(D, ResilienceExpansion::Minimal)) {
struct ThunkEmitter : public SILVTableVisitor<ThunkEmitter> {
IRGenModule &IGM;
ClassDecl *D;

ThunkEmitter(IRGenModule &IGM, ClassDecl *D)
: IGM(IGM), D(D) {
addVTableEntries(D);
}

void addMethodOverride(SILDeclRef baseRef, SILDeclRef declRef) {}

void addMethod(SILDeclRef member) {
auto *func = cast<AbstractFunctionDecl>(member.getDecl());
if (func->getDeclContext() == D &&
func->getEffectiveAccess() >= AccessLevel::Public) {
IGM.emitDispatchThunk(member);
}
}

void addPlaceholder(MissingMemberDecl *m) {
assert(m->getNumberOfVTableEntries() == 0
&& "Should not be emitting class with missing members");
}
};

ThunkEmitter emitter(*this, D);
}
}

namespace {
Expand Down
97 changes: 54 additions & 43 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,7 +1378,10 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
switch (getKind()) {
case Kind::DispatchThunk:
case Kind::DispatchThunkInitializer:
case Kind::DispatchThunkAllocator: {
case Kind::DispatchThunkAllocator:
case Kind::MethodDescriptor:
case Kind::MethodDescriptorInitializer:
case Kind::MethodDescriptorAllocator: {
auto *decl = getDecl();

// Protocol requirements don't have their own access control
Expand Down Expand Up @@ -1586,7 +1589,10 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
switch (getKind()) {
case Kind::DispatchThunk:
case Kind::DispatchThunkInitializer:
case Kind::DispatchThunkAllocator: {
case Kind::DispatchThunkAllocator:
case Kind::MethodDescriptor:
case Kind::MethodDescriptorInitializer:
case Kind::MethodDescriptorAllocator: {
auto *decl = getDecl();

// Protocol requirements don't have their own access control
Expand Down Expand Up @@ -3268,6 +3274,47 @@ IRGenModule::getAddrOfTypeMetadataSingletonInitializationCache(
return variable;
}

llvm::GlobalValue *IRGenModule::defineAlias(LinkEntity entity,
llvm::Constant *definition) {
// Check for an existing forward declaration of the alias.
auto &entry = GlobalVars[entity];
llvm::GlobalValue *existingVal = nullptr;
if (entry) {
existingVal = cast<llvm::GlobalValue>(entry);
// Clear the existing value's name so we can steal it.
existingVal->setName("");
}

LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
auto *ptrTy = cast<llvm::PointerType>(definition->getType());
auto *alias = llvm::GlobalAlias::create(
ptrTy->getElementType(), ptrTy->getAddressSpace(), link.getLinkage(),
link.getName(), definition, &Module);
alias->setVisibility(link.getVisibility());
alias->setDLLStorageClass(link.getDLLStorage());

if (link.isUsed()) {
addUsedGlobal(alias);
}

// Replace an existing external declaration for the address point.
if (entry) {
auto existingVal = cast<llvm::GlobalValue>(entry);

// FIXME: MC breaks when emitting alias references on some platforms
// (rdar://problem/22450593 ). Work around this by referring to the aliasee
// instead.
llvm::Constant *aliasCast = alias->getAliasee();
aliasCast = llvm::ConstantExpr::getBitCast(aliasCast,
entry->getType());
existingVal->replaceAllUsesWith(aliasCast);
existingVal->eraseFromParent();
}
entry = alias;

return alias;
}

/// Define the metadata for a type.
///
/// Some type metadata has information before the address point that the
Expand Down Expand Up @@ -3320,6 +3367,10 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
if (!section.empty())
var->setSection(section);

LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
if (link.isUsed())
addUsedGlobal(var);

// Keep type metadata around for all types.
if (auto nominal = concreteType->getAnyNominal())
addRuntimeResolvableType(nominal);
Expand All @@ -3339,47 +3390,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
addr, indices);
}
addr = llvm::ConstantExpr::getBitCast(addr, TypeMetadataPtrTy);

// Check for an existing forward declaration of the address point.
auto &directEntry = GlobalVars[directEntity];
llvm::GlobalValue *existingVal = nullptr;
if (directEntry) {
existingVal = cast<llvm::GlobalValue>(directEntry);
// Clear the existing value's name so we can steal it.
existingVal->setName("");
}

LinkInfo link = LinkInfo::get(*this, directEntity, ForDefinition);
auto *ptrTy = cast<llvm::PointerType>(addr->getType());
auto *alias = llvm::GlobalAlias::create(
ptrTy->getElementType(), ptrTy->getAddressSpace(), link.getLinkage(),
link.getName(), addr, &Module);
alias->setVisibility(link.getVisibility());
alias->setDLLStorageClass(link.getDLLStorage());

// The full metadata is used based on the visibility of the address point,
// not the metadata itself.
if (link.isUsed()) {
addUsedGlobal(var);
addUsedGlobal(alias);
}

// Replace an existing external declaration for the address point.
if (directEntry) {
auto existingVal = cast<llvm::GlobalValue>(directEntry);

// FIXME: MC breaks when emitting alias references on some platforms
// (rdar://problem/22450593 ). Work around this by referring to the aliasee
// instead.
llvm::Constant *aliasCast = alias->getAliasee();
aliasCast = llvm::ConstantExpr::getBitCast(aliasCast,
directEntry->getType());
existingVal->replaceAllUsesWith(aliasCast);
existingVal->eraseFromParent();
}
directEntry = alias;

return alias;
return defineAlias(directEntity, addr);
}

/// Fetch the declaration of the metadata (or metadata template) for a
Expand Down
Loading