mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
584 lines
19 KiB
C++
584 lines
19 KiB
C++
//===--- IRGenMangler.cpp - mangling of IRGen symbols ---------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "IRGenMangler.h"
|
|
#include "ExtendedExistential.h"
|
|
#include "GenClass.h"
|
|
#include "IRGenModule.h"
|
|
#include "swift/AST/ExistentialLayout.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/AST/ProtocolAssociations.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Platform.h"
|
|
#include "swift/Demangling/ManglingMacros.h"
|
|
#include "swift/Demangling/Demangle.h"
|
|
#include "swift/ABI/MetadataValues.h"
|
|
#include "swift/ClangImporter/ClangModule.h"
|
|
#include "llvm/Support/SaveAndRestore.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
const char *getManglingForWitness(swift::Demangle::ValueWitnessKind kind) {
|
|
switch (kind) {
|
|
#define VALUE_WITNESS(MANGLING, NAME) \
|
|
case swift::Demangle::ValueWitnessKind::NAME: return #MANGLING;
|
|
#include "swift/Demangling/ValueWitnessMangling.def"
|
|
}
|
|
llvm_unreachable("not a function witness");
|
|
}
|
|
|
|
std::string IRGenMangler::mangleValueWitness(Type type, ValueWitness witness) {
|
|
beginMangling();
|
|
appendType(type, nullptr);
|
|
|
|
const char *Code = nullptr;
|
|
switch (witness) {
|
|
#define GET_MANGLING(ID) \
|
|
case ValueWitness::ID: Code = getManglingForWitness(swift::Demangle::ValueWitnessKind::ID); break;
|
|
GET_MANGLING(InitializeBufferWithCopyOfBuffer) \
|
|
GET_MANGLING(Destroy) \
|
|
GET_MANGLING(InitializeWithCopy) \
|
|
GET_MANGLING(AssignWithCopy) \
|
|
GET_MANGLING(InitializeWithTake) \
|
|
GET_MANGLING(AssignWithTake) \
|
|
GET_MANGLING(GetEnumTagSinglePayload) \
|
|
GET_MANGLING(StoreEnumTagSinglePayload) \
|
|
GET_MANGLING(GetEnumTag) \
|
|
GET_MANGLING(DestructiveProjectEnumData) \
|
|
GET_MANGLING(DestructiveInjectEnumTag)
|
|
#undef GET_MANGLING
|
|
case ValueWitness::Size:
|
|
case ValueWitness::Flags:
|
|
case ValueWitness::ExtraInhabitantCount:
|
|
case ValueWitness::Stride:
|
|
llvm_unreachable("not a function witness");
|
|
}
|
|
appendOperator("w", Code);
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::manglePartialApplyForwarder(StringRef FuncName) {
|
|
if (FuncName.empty()) {
|
|
beginMangling();
|
|
} else {
|
|
if (FuncName.starts_with(MANGLING_PREFIX_STR) ||
|
|
FuncName.starts_with(MANGLING_PREFIX_EMBEDDED_STR)) {
|
|
Buffer << FuncName;
|
|
} else {
|
|
beginMangling();
|
|
appendIdentifier(FuncName);
|
|
}
|
|
}
|
|
appendOperator("TA");
|
|
return finalize();
|
|
}
|
|
|
|
SymbolicMangling
|
|
IRGenMangler::withSymbolicReferences(IRGenModule &IGM,
|
|
llvm::function_ref<void ()> body) {
|
|
Mod = IGM.getSwiftModule();
|
|
configureForSymbolicMangling();
|
|
|
|
llvm::SaveAndRestore<bool>
|
|
AllowSymbolicReferencesLocally(AllowSymbolicReferences);
|
|
llvm::SaveAndRestore<std::function<bool (SymbolicReferent)>>
|
|
CanSymbolicReferenceLocally(CanSymbolicReference);
|
|
|
|
AllowSymbolicReferences = true;
|
|
CanSymbolicReference = [&](SymbolicReferent s) -> bool {
|
|
switch (s.getKind()) {
|
|
case SymbolicReferent::NominalType: {
|
|
auto type = s.getNominalType();
|
|
// The short-substitution types in the standard library have compact
|
|
// manglings already, and the runtime ought to have a lookup table for
|
|
// them. Symbolic referencing would be wasteful.
|
|
if (AllowStandardSubstitutions
|
|
&& type->getModuleContext()->hasStandardSubstitutions()
|
|
&& Mangle::getStandardTypeSubst(
|
|
type->getName().str(), AllowConcurrencyStandardSubstitutions)) {
|
|
return false;
|
|
}
|
|
|
|
// TODO: We could assign a symbolic reference discriminator to refer
|
|
// to objc protocol refs.
|
|
if (auto proto = dyn_cast<ProtocolDecl>(type)) {
|
|
if (proto->isObjC() && !IGM.canUseObjCSymbolicReferences()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Classes defined in Objective-C don't have descriptors.
|
|
// TODO: We could assign a symbolic reference discriminator to refer
|
|
// to objc class refs.
|
|
if (auto clazz = dyn_cast<ClassDecl>(type)) {
|
|
// Swift-defined classes can be symbolically referenced.
|
|
if (hasKnownSwiftMetadata(IGM, const_cast<ClassDecl*>(clazz)))
|
|
return true;
|
|
|
|
// Foreign class types can be symbolically referenced.
|
|
if (clazz->getForeignClassKind() == ClassDecl::ForeignKind::CFType ||
|
|
const_cast<ClassDecl *>(clazz)->isForeignReferenceType())
|
|
return true;
|
|
|
|
// Otherwise no.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
case SymbolicReferent::OpaqueType:
|
|
// Always symbolically reference opaque types.
|
|
return true;
|
|
case SymbolicReferent::ExtendedExistentialTypeShape:
|
|
// Always symbolically reference extended existential type shapes.
|
|
return true;
|
|
}
|
|
llvm_unreachable("symbolic referent not handled");
|
|
};
|
|
|
|
SymbolicReferences.clear();
|
|
|
|
body();
|
|
|
|
return {finalize(), std::move(SymbolicReferences)};
|
|
}
|
|
|
|
SymbolicMangling
|
|
IRGenMangler::mangleTypeForReflection(IRGenModule &IGM,
|
|
CanGenericSignature Sig,
|
|
CanType Ty) {
|
|
// If our target predates Swift 5.5, we cannot apply the standard
|
|
// substitutions for types defined in the Concurrency module.
|
|
ASTContext &ctx = Ty->getASTContext();
|
|
llvm::SaveAndRestore<bool> savedConcurrencyStandardSubstitutions(
|
|
AllowConcurrencyStandardSubstitutions);
|
|
llvm::SaveAndRestore<bool> savedIsolatedAny(AllowIsolatedAny);
|
|
llvm::SaveAndRestore<bool> savedTypedThrows(AllowTypedThrows);
|
|
if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
|
|
ctx.LangOpts.Target)) {
|
|
|
|
if (*runtimeCompatVersion < llvm::VersionTuple(5, 5))
|
|
AllowConcurrencyStandardSubstitutions = false;
|
|
|
|
// Suppress @isolated(any) and typed throws if we're mangling for pre-6.0
|
|
// runtimes.
|
|
// This is unprincipled but, because of the restrictions in e.g.
|
|
// mangledNameIsUnknownToDeployTarget, should only happen when
|
|
// mangling for certain reflective uses where we have to hope that
|
|
// the exact type identity is generally unimportant.
|
|
if (*runtimeCompatVersion < llvm::VersionTuple(6, 0)) {
|
|
AllowIsolatedAny = false;
|
|
AllowTypedThrows = false;
|
|
}
|
|
}
|
|
|
|
llvm::SaveAndRestore<bool> savedAllowStandardSubstitutions(
|
|
AllowStandardSubstitutions);
|
|
if (IGM.getOptions().DisableStandardSubstitutionsInReflectionMangling)
|
|
AllowStandardSubstitutions = false;
|
|
|
|
llvm::SaveAndRestore<bool> savedAllowMarkerProtocols(
|
|
AllowMarkerProtocols, false);
|
|
return withSymbolicReferences(IGM, [&]{
|
|
appendType(Ty, Sig);
|
|
});
|
|
}
|
|
|
|
SymbolicMangling
|
|
IRGenMangler::mangleTypeForFlatUniqueTypeRef(CanGenericSignature sig,
|
|
CanType type) {
|
|
// Use runtime information like we would for a symbolic mangling,
|
|
// just don't allow actual symbolic references anywhere in the
|
|
// mangled name.
|
|
configureForSymbolicMangling();
|
|
|
|
llvm::SaveAndRestore<bool> savedAllowMarkerProtocols(
|
|
AllowMarkerProtocols, false);
|
|
|
|
// We don't make the substitution adjustments above because they're
|
|
// target-specific and so would break the goal of getting a unique
|
|
// string.
|
|
appendType(type, sig);
|
|
|
|
assert(SymbolicReferences.empty());
|
|
return {finalize(), {}};
|
|
}
|
|
|
|
std::string IRGenMangler::mangleProtocolConformanceDescriptor(
|
|
const RootProtocolConformance *conformance) {
|
|
llvm::SaveAndRestore X(AllowInverses,
|
|
inversesAllowedIn(conformance->getDeclContext()));
|
|
|
|
beginMangling();
|
|
if (isa<NormalProtocolConformance>(conformance)) {
|
|
appendProtocolConformance(conformance);
|
|
appendOperator("Mc");
|
|
} else {
|
|
auto protocol = cast<SelfProtocolConformance>(conformance)->getProtocol();
|
|
appendProtocolName(protocol);
|
|
appendOperator("MS");
|
|
}
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleProtocolConformanceDescriptorRecord(
|
|
const RootProtocolConformance *conformance) {
|
|
llvm::SaveAndRestore X(AllowInverses,
|
|
inversesAllowedIn(conformance->getDeclContext()));
|
|
|
|
beginMangling();
|
|
appendProtocolConformance(conformance);
|
|
appendOperator("Hc");
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleProtocolConformanceInstantiationCache(
|
|
const RootProtocolConformance *conformance) {
|
|
llvm::SaveAndRestore X(AllowInverses,
|
|
inversesAllowedIn(conformance->getDeclContext()));
|
|
|
|
beginMangling();
|
|
if (isa<NormalProtocolConformance>(conformance)) {
|
|
appendProtocolConformance(conformance);
|
|
appendOperator("Mc");
|
|
} else {
|
|
auto protocol = cast<SelfProtocolConformance>(conformance)->getProtocol();
|
|
appendProtocolName(protocol);
|
|
appendOperator("MS");
|
|
}
|
|
appendOperator("MK");
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleTypeForLLVMTypeName(CanType Ty) {
|
|
// To make LLVM IR more readable we always add a 'T' prefix so that type names
|
|
// don't start with a digit and don't need to be quoted.
|
|
Buffer << 'T';
|
|
if (Ty->is<ExistentialType>() && Ty->hasParameterizedExistential()) {
|
|
appendType(Ty, nullptr);
|
|
} else {
|
|
if (auto existential = Ty->getAs<ExistentialType>())
|
|
Ty = existential->getConstraintType()->getCanonicalType();
|
|
if (auto P = dyn_cast<ProtocolType>(Ty)) {
|
|
appendProtocolName(P->getDecl(), /*allowStandardSubstitution=*/false);
|
|
appendOperator("P");
|
|
} else {
|
|
appendType(Ty, nullptr);
|
|
}
|
|
}
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::
|
|
mangleProtocolForLLVMTypeName(ProtocolCompositionType *type) {
|
|
ExistentialLayout layout = type->getExistentialLayout();
|
|
|
|
if (type->isAny()) {
|
|
Buffer << "Any";
|
|
} else if (layout.isAnyObject()) {
|
|
Buffer << "AnyObject";
|
|
} else {
|
|
// To make LLVM IR more readable we always add a 'T' prefix so that type names
|
|
// don't start with a digit and don't need to be quoted.
|
|
Buffer << 'T';
|
|
bool isFirstItem = true;
|
|
InvertibleProtocolSet inverses = InvertibleProtocolSet::allKnown();
|
|
auto protocols = layout.getProtocols();
|
|
for (auto *proto : protocols) {
|
|
if (auto ip = proto->getInvertibleProtocolKind()) {
|
|
inverses.remove(*ip);
|
|
continue;
|
|
}
|
|
|
|
appendProtocolName(proto);
|
|
appendListSeparator(isFirstItem);
|
|
}
|
|
// Append inverses like '~Copyable' as '-Copyable'
|
|
for (auto ip : inverses) {
|
|
appendOperator("-");
|
|
appendIdentifier(getProtocolName(getKnownProtocolKind(ip)));
|
|
appendListSeparator(isFirstItem);
|
|
}
|
|
if (auto superclass = layout.explicitSuperclass) {
|
|
// We share type infos for different instantiations of a generic type
|
|
// when the archetypes have the same exemplars. We cannot mangle
|
|
// archetypes, and the mangling does not have to be unique, so we just
|
|
// mangle the unbound generic form of the type.
|
|
if (superclass->hasArchetype()) {
|
|
superclass = superclass->getClassOrBoundGenericClass()
|
|
->getDeclaredType();
|
|
}
|
|
|
|
appendType(CanType(superclass), nullptr);
|
|
appendOperator("Xc");
|
|
} else if (layout.getLayoutConstraint()) {
|
|
appendOperator("Xl");
|
|
} else {
|
|
appendOperator("p");
|
|
}
|
|
}
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::
|
|
mangleSymbolNameForSymbolicMangling(const SymbolicMangling &mangling,
|
|
MangledTypeRefRole role) {
|
|
beginManglingWithoutPrefix();
|
|
const char *prefix;
|
|
switch (role) {
|
|
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
|
|
prefix = "default assoc type ";
|
|
break;
|
|
|
|
case MangledTypeRefRole::FieldMetadata:
|
|
case MangledTypeRefRole::Metadata:
|
|
case MangledTypeRefRole::Reflection:
|
|
prefix = "symbolic ";
|
|
break;
|
|
|
|
case MangledTypeRefRole::FlatUnique:
|
|
prefix = "flat unique ";
|
|
assert(mangling.SymbolicReferences.empty());
|
|
break;
|
|
}
|
|
auto prefixLen = strlen(prefix);
|
|
|
|
Buffer << prefix << mangling.String;
|
|
|
|
for (auto &symbol : mangling.SymbolicReferences) {
|
|
// Fill in the placeholder space with something printable.
|
|
auto referent = symbol.first;
|
|
auto offset = symbol.second;
|
|
Storage[prefixLen + offset]
|
|
= Storage[prefixLen + offset+1]
|
|
= Storage[prefixLen + offset+2]
|
|
= Storage[prefixLen + offset+3]
|
|
= Storage[prefixLen + offset+4]
|
|
= '_';
|
|
Buffer << ' ';
|
|
switch (referent.getKind()) {
|
|
case SymbolicReferent::NominalType: {
|
|
auto ty = referent.getNominalType();
|
|
BaseEntitySignature base(ty);
|
|
appendContext(ty, base, ty->getAlternateModuleName());
|
|
continue;
|
|
}
|
|
case SymbolicReferent::OpaqueType: {
|
|
appendOpaqueDeclName(referent.getOpaqueType());
|
|
continue;
|
|
}
|
|
case SymbolicReferent::ExtendedExistentialTypeShape: {
|
|
auto existentialType = referent.getType()->getCanonicalType();
|
|
auto shapeInfo =
|
|
ExtendedExistentialTypeShapeInfo::get(existentialType);
|
|
appendExtendedExistentialTypeShapeSymbol(shapeInfo.genSig,
|
|
shapeInfo.shapeType,
|
|
shapeInfo.isUnique());
|
|
continue;
|
|
}
|
|
}
|
|
llvm_unreachable("unhandled referent");
|
|
}
|
|
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleSymbolNameForAssociatedConformanceWitness(
|
|
const NormalProtocolConformance *conformance,
|
|
CanType associatedType,
|
|
const ProtocolDecl *proto) {
|
|
beginManglingWithoutPrefix();
|
|
if (conformance) {
|
|
Buffer << "associated conformance ";
|
|
appendProtocolConformance(conformance);
|
|
} else {
|
|
Buffer << "default associated conformance";
|
|
}
|
|
|
|
bool isFirstAssociatedTypeIdentifier = true;
|
|
appendAssociatedTypePath(associatedType, isFirstAssociatedTypeIdentifier);
|
|
appendProtocolName(proto);
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleSymbolNameForMangledMetadataAccessorString(
|
|
const char *kind,
|
|
CanGenericSignature genericSig,
|
|
CanType type,
|
|
MangledTypeRefRole role) {
|
|
beginManglingWithoutPrefix();
|
|
Buffer << kind << " ";
|
|
|
|
if (genericSig) {
|
|
appendGenericSignature(genericSig);
|
|
}
|
|
|
|
if (type) {
|
|
appendType(type, genericSig);
|
|
}
|
|
|
|
// Noncopyable types get additional runtime capability checks before we reveal
|
|
// their metadata to reflection APIs, while core metadata queries always provide
|
|
// the metadata. So we need a separate symbol mangling for the two variants in
|
|
// this case.
|
|
switch (role) {
|
|
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
|
|
case MangledTypeRefRole::FlatUnique:
|
|
case MangledTypeRefRole::Metadata:
|
|
// Core metadata, never conditionalized.
|
|
break;
|
|
|
|
case MangledTypeRefRole::Reflection:
|
|
case MangledTypeRefRole::FieldMetadata: {
|
|
// Reflection metadata is conditionalized for noncopyable types.
|
|
CanType contextType = type;
|
|
if (genericSig) {
|
|
contextType = genericSig.getGenericEnvironment()->mapTypeIntoEnvironment(contextType)
|
|
->getReducedType(genericSig);
|
|
}
|
|
if (contextType->isNoncopyable()) {
|
|
Buffer << " noncopyable";
|
|
}
|
|
}
|
|
}
|
|
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleSymbolNameForMangledConformanceAccessorString(
|
|
const char *kind,
|
|
CanGenericSignature genericSig,
|
|
CanType type,
|
|
ProtocolConformanceRef conformance) {
|
|
beginManglingWithoutPrefix();
|
|
Buffer << kind << " ";
|
|
|
|
if (genericSig)
|
|
appendGenericSignature(genericSig);
|
|
|
|
appendAnyProtocolConformance(genericSig, type, conformance);
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleSymbolNameForMangledGetEnumTagForLayoutString(
|
|
CanType type) {
|
|
beginManglingWithoutPrefix();
|
|
Buffer << "get_enum_tag_for_layout_string"
|
|
<< " ";
|
|
|
|
appendType(type, nullptr);
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleSymbolNameForUnderlyingTypeAccessorString(
|
|
OpaqueTypeDecl *opaque, unsigned index) {
|
|
beginManglingWithoutPrefix();
|
|
Buffer << "get_underlying_type_ref ";
|
|
|
|
BaseEntitySignature base(opaque);
|
|
appendContextOf(opaque, base);
|
|
appendOpaqueDeclName(opaque);
|
|
|
|
if (index == 0) {
|
|
appendOperator("Qr");
|
|
} else {
|
|
appendOperator("QR", Index(index));
|
|
}
|
|
|
|
return finalize();
|
|
}
|
|
|
|
std::string
|
|
IRGenMangler::mangleSymbolNameForUnderlyingWitnessTableAccessorString(
|
|
OpaqueTypeDecl *opaque, const Requirement &req, ProtocolDecl *protocol) {
|
|
beginManglingWithoutPrefix();
|
|
Buffer << "get_underlying_witness ";
|
|
|
|
BaseEntitySignature base(opaque);
|
|
appendContextOf(opaque, base);
|
|
appendOpaqueDeclName(opaque);
|
|
|
|
appendType(req.getFirstType()->getCanonicalType(), opaque->getGenericSignature());
|
|
|
|
appendProtocolName(protocol);
|
|
|
|
appendOperator("HC");
|
|
|
|
return finalize();
|
|
}
|
|
|
|
std::string IRGenMangler::mangleSymbolNameForGenericEnvironment(
|
|
CanGenericSignature genericSig) {
|
|
beginManglingWithoutPrefix();
|
|
Buffer << "generic environment ";
|
|
appendGenericSignature(genericSig);
|
|
return finalize();
|
|
}
|
|
|
|
std::string
|
|
IRGenMangler::mangleExtendedExistentialTypeShapeSymbol(
|
|
CanGenericSignature genSig,
|
|
CanType shapeType,
|
|
bool isUnique) {
|
|
beginMangling();
|
|
appendExtendedExistentialTypeShapeSymbol(genSig, shapeType, isUnique);
|
|
return finalize();
|
|
}
|
|
|
|
void
|
|
IRGenMangler::appendExtendedExistentialTypeShapeSymbol(
|
|
CanGenericSignature genSig,
|
|
CanType shapeType,
|
|
bool isUnique) {
|
|
appendExtendedExistentialTypeShape(genSig, shapeType);
|
|
|
|
// If this is non-unique, add a suffix to avoid accidental misuse
|
|
// (and to make it easier to analyze in an image).
|
|
if (!isUnique)
|
|
appendOperator("Mq");
|
|
}
|
|
|
|
void
|
|
IRGenMangler::appendExtendedExistentialTypeShape(CanGenericSignature genSig,
|
|
CanType shapeType) {
|
|
// Append the generalization signature.
|
|
if (genSig) {
|
|
// Generalization signature never mangles inverses.
|
|
llvm::SaveAndRestore X(AllowInverses, false);
|
|
appendGenericSignature(genSig);
|
|
}
|
|
|
|
// Append the existential type.
|
|
appendType(shapeType, genSig);
|
|
|
|
// Append the shape operator.
|
|
appendOperator(genSig ? "XG" : "Xg");
|
|
}
|
|
|
|
std::string
|
|
IRGenMangler::mangleConformanceSymbol(Type type,
|
|
const ProtocolConformance *Conformance,
|
|
const char *Op) {
|
|
llvm::SaveAndRestore X(AllowInverses,
|
|
inversesAllowedIn(Conformance->getDeclContext()));
|
|
|
|
beginMangling();
|
|
if (type)
|
|
appendType(type, nullptr);
|
|
appendProtocolConformance(Conformance);
|
|
appendOperator(Op);
|
|
return finalize();
|
|
}
|