Files
swift-mirror/lib/IRGen/IRSymbolVisitor.cpp
Konrad 'ktoso' Malawski 957a95be63 [Distributed] Distributed actor usage through protocol with lib-evo must work
This corrects how we were dealing with dispatch thunks -- mostly be
removing a lot of special casing we did but doesn't seem necessary and
instead we correct and emit all the necessary information int TBD.

This builds on  https://github.com/swiftlang/swift/pull/74935 by further refining how we fixed that issue, and adds more regression tests. It also removes a load of special casing of distributed thunks in library evolution mode, which is great.

Resolves and adds regression test for for rdar://145292018

This is also a more proper fix to the previously resolved but in a not-great-way which caused other issues:
- resolves rdar://128284016
- resolves rdar://128310903
2025-04-18 11:21:01 +09:00

259 lines
8.9 KiB
C++

//===--- IRSymbolVisitor.cpp - IR Linker Symbol Visitor ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements liker symbol enumeration for IRSymbolVisitor.
//
//===----------------------------------------------------------------------===//
#include "swift/IRGen/IRSymbolVisitor.h"
#include "swift/SIL/SILSymbolVisitor.h"
using namespace swift;
using namespace irgen;
/// Determine whether dynamic replacement should be emitted for the allocator or
/// the initializer given a decl. The rule is that structs and convenience init
/// of classes emit a dynamic replacement for the allocator. A designated init
/// of a class emits a dynamic replacement for the initializer. This is because
/// the super class init call is emitted to the initializer and needs to be
/// dynamic.
static bool shouldUseAllocatorMangling(const AbstractFunctionDecl *AFD) {
auto constructor = dyn_cast<ConstructorDecl>(AFD);
if (!constructor)
return false;
return constructor->getParent()->getSelfClassDecl() == nullptr ||
constructor->isConvenienceInit();
}
/// The underlying implementation of the IR symbol visitor logic. This class is
/// responsible for overriding the abstract methods of `SILSymbolVisitor` and
/// emitting `LinkEntity` instances to the downstream visitor in addition to
/// passing through `SILDeclRef`s produced by the SIL symbol visitor.
class IRSymbolVisitorImpl : public SILSymbolVisitor {
IRSymbolVisitor &Visitor;
const IRSymbolVisitorContext &Ctx;
bool PublicOrPackageSymbolsOnly;
/// Emits the given `LinkEntity` to the downstream visitor as long as the
/// entity has the required linkage.
///
/// FIXME: The need for an ignoreVisibility flag here possibly indicates that
/// there is something broken about the linkage computation below.
void addLinkEntity(LinkEntity entity, bool ignoreVisibility = false) {
if (!ignoreVisibility) {
auto linkage =
LinkInfo::get(Ctx.getLinkInfo(), Ctx.getSILCtx().getModule(), entity,
ForDefinition);
auto externallyVisible =
llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) &&
linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility;
if (PublicOrPackageSymbolsOnly && !externallyVisible)
return;
}
Visitor.addLinkEntity(entity);
}
public:
IRSymbolVisitorImpl(IRSymbolVisitor &Visitor,
const IRSymbolVisitorContext &Ctx)
: Visitor{Visitor}, Ctx{Ctx},
PublicOrPackageSymbolsOnly{Ctx.getSILCtx().getOpts().PublicOrPackageSymbolsOnly} {}
bool willVisitDecl(Decl *D) override {
return Visitor.willVisitDecl(D);
}
void didVisitDecl(Decl *D) override {
Visitor.didVisitDecl(D);
}
void addAssociatedConformanceDescriptor(AssociatedConformance AC) override {
addLinkEntity(LinkEntity::forAssociatedConformanceDescriptor(AC));
}
void addAssociatedTypeDescriptor(AssociatedTypeDecl *ATD) override {
addLinkEntity(LinkEntity::forAssociatedTypeDescriptor(ATD));
}
void addAsyncFunctionPointer(SILDeclRef declRef) override {
addLinkEntity(LinkEntity::forAsyncFunctionPointer(declRef),
/*ignoreVisibility=*/true);
}
void addBaseConformanceDescriptor(BaseConformance BC) override {
addLinkEntity(LinkEntity::forBaseConformanceDescriptor(BC));
}
void addClassMetadataBaseOffset(ClassDecl *CD) override {
addLinkEntity(LinkEntity::forClassMetadataBaseOffset(CD));
}
void addCoroFunctionPointer(SILDeclRef declRef) override {
addLinkEntity(LinkEntity::forCoroFunctionPointer(declRef),
/*ignoreVisibility=*/true);
}
void addDispatchThunk(SILDeclRef declRef) override {
auto entity = LinkEntity::forDispatchThunk(declRef);
addLinkEntity(entity);
if (declRef.getAbstractFunctionDecl()->hasAsync())
addLinkEntity(LinkEntity::forAsyncFunctionPointer(entity));
auto *accessor = dyn_cast<AccessorDecl>(declRef.getAbstractFunctionDecl());
if (accessor &&
requiresFeatureCoroutineAccessors(accessor->getAccessorKind()))
addLinkEntity(LinkEntity::forCoroFunctionPointer(entity));
}
void addDynamicFunction(AbstractFunctionDecl *AFD,
DynamicKind dynKind) override {
bool useAllocator = shouldUseAllocatorMangling(AFD);
addLinkEntity(LinkEntity::forDynamicallyReplaceableFunctionVariable(
AFD, useAllocator));
switch (dynKind) {
case DynamicKind::Replaceable:
addLinkEntity(
LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator));
break;
case DynamicKind::Replacement:
addLinkEntity(
LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator));
break;
}
}
void addEnumCase(EnumElementDecl *EED) override {
addLinkEntity(LinkEntity::forEnumCase(EED));
}
void addFieldOffset(VarDecl *VD) override {
addLinkEntity(LinkEntity::forFieldOffset(VD));
}
void addFunction(SILDeclRef declRef) override {
Visitor.addFunction(declRef);
}
void addFunction(StringRef name, SILDeclRef declRef) override {
Visitor.addFunction(name, declRef);
}
void addGlobalVar(VarDecl *VD) override {
Visitor.addGlobalVar(VD);
}
void addMethodDescriptor(SILDeclRef declRef) override {
addLinkEntity(LinkEntity::forMethodDescriptor(declRef));
}
void addMethodLookupFunction(ClassDecl *CD) override {
addLinkEntity(LinkEntity::forMethodLookupFunction(CD));
}
void addNominalTypeDescriptor(NominalTypeDecl *NTD) override {
addLinkEntity(LinkEntity::forNominalTypeDescriptor(NTD));
}
void addObjCInterface(ClassDecl *CD) override {
Visitor.addObjCInterface(CD);
}
void addObjCMetaclass(ClassDecl *CD) override {
addLinkEntity(LinkEntity::forObjCMetaclass(CD));
}
void addObjCMethod(AbstractFunctionDecl *AFD) override {
// Pass through; Obj-C methods don't have linkable symbols.
Visitor.addObjCMethod(AFD);
}
void addObjCResilientClassStub(ClassDecl *CD) override {
addLinkEntity(LinkEntity::forObjCResilientClassStub(
CD, TypeMetadataAddress::AddressPoint));
}
void addOpaqueTypeDescriptor(OpaqueTypeDecl *OTD) override {
addLinkEntity(LinkEntity::forOpaqueTypeDescriptor(OTD));
}
void addOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *OTD,
DynamicKind dynKind) override {
addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessor(OTD));
switch (dynKind) {
case DynamicKind::Replaceable:
addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(OTD));
addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessorKey(OTD));
break;
case DynamicKind::Replacement:
break;
}
addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessorVar(OTD));
}
void addPropertyDescriptor(AbstractStorageDecl *ASD) override {
addLinkEntity(LinkEntity::forPropertyDescriptor(ASD));
}
void addProtocolConformanceDescriptor(RootProtocolConformance *C) override {
addLinkEntity(LinkEntity::forProtocolConformanceDescriptor(C));
}
void addProtocolDescriptor(ProtocolDecl *PD) override {
addLinkEntity(LinkEntity::forProtocolDescriptor(PD));
}
void addProtocolRequirementsBaseDescriptor(ProtocolDecl *PD) override {
addLinkEntity(LinkEntity::forProtocolRequirementsBaseDescriptor(PD));
}
void addProtocolWitnessTable(RootProtocolConformance *C) override {
addLinkEntity(LinkEntity::forProtocolWitnessTable(C));
}
void addProtocolWitnessThunk(RootProtocolConformance *C,
ValueDecl *requirementDecl) override {
Visitor.addProtocolWitnessThunk(C, requirementDecl);
}
void addSwiftMetaclassStub(ClassDecl *CD) override {
addLinkEntity(LinkEntity::forSwiftMetaclassStub(CD));
}
void addTypeMetadataAccessFunction(CanType T) override {
addLinkEntity(LinkEntity::forTypeMetadataAccessFunction(T));
}
void addTypeMetadataAddress(CanType T) override {
addLinkEntity(
LinkEntity::forTypeMetadata(T, TypeMetadataAddress::AddressPoint));
}
};
void IRSymbolVisitor::visit(Decl *D, const IRSymbolVisitorContext &Ctx) {
IRSymbolVisitorImpl(*this, Ctx).visitDecl(D, Ctx.getSILCtx());
}
void IRSymbolVisitor::visitFile(FileUnit *file,
const IRSymbolVisitorContext &Ctx) {
IRSymbolVisitorImpl(*this, Ctx).visitFile(file, Ctx.getSILCtx());
}
void IRSymbolVisitor::visitModules(llvm::SmallVector<ModuleDecl *, 4> &modules,
const IRSymbolVisitorContext &Ctx) {
IRSymbolVisitorImpl(*this, Ctx).visitModules(modules, Ctx.getSILCtx());
}